Hystrix降级技术解析-Fallback


声明:本文转载自https://my.oschina.net/wangxindong/blog/1518994,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

一、降级

所谓降级,就是指在在Hystrix执行非核心链路功能失败的情况下,我们如何处理,比如我们返回默认值等。如果我们要回退或者降级处理,代码上需要实现HystrixCommand.getFallback()方法或者是HystrixObservableCommand. HystrixObservableCommand()。

public class CommandHelloFailure extends HystrixCommand<String> {      private final String name;      public CommandHelloFailure(String name) {         super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));         this.name = name;     }      @Override     protected String run() {         throw new RuntimeException("this command always fails");     }      @Override     protected String getFallback() {         return "Hello Failure " + name + "!";     } } 

二、Hystrix的降级回退方式

Hystrix一共有如下几种降级回退模式:

1、Fail Fast 快速失败

 @Override     protected String run() {         if (throwException) {             throw new RuntimeException("failure from CommandThatFailsFast");         } else {             return "success";         }     } 

如果我们实现的是HystrixObservableCommand.java则 重写 resumeWithFallback方法

@Override     protected Observable<String> resumeWithFallback() {         if (throwException) {             return Observable.error(new Throwable("failure from CommandThatFailsFast"));         } else {             return Observable.just("success");         }     } 

2、Fail Silent 无声失败

返回null,空Map,空List

fail silent.png

fail silent.png

@Override     protected String getFallback() {         return null;     } @Override     protected List<String> getFallback() {         return Collections.emptyList();     } @Override     protected Observable<String> resumeWithFallback() {         return Observable.empty();     } 

3、Fallback: Static 返回默认值

回退的时候返回静态嵌入代码中的默认值,这样就不会导致功能以Fail Silent的方式被清楚,也就是用户看不到任何功能了。而是按照一个默认的方式显示。

@Override     protected Boolean getFallback() {         return true;     } @Override     protected Observable<Boolean> resumeWithFallback() {         return Observable.just( true );     } 

4、Fallback: Stubbed 自己组装一个值返回

当我们执行返回的结果是一个包含多个字段的对象时,则会以Stubbed 的方式回退。Stubbed 值我们建议在实例化Command的时候就设置好一个值。以countryCodeFromGeoLookup为例,countryCodeFromGeoLookup的值,是在我们调用的时候就注册进来初始化好的。CommandWithStubbedFallback command = new CommandWithStubbedFallback(1234, "china");主要代码如下:

public class CommandWithStubbedFallback extends HystrixCommand<UserAccount> {  protected CommandWithStubbedFallback(int customerId, String countryCodeFromGeoLookup) {         super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));         this.customerId = customerId;         this.countryCodeFromGeoLookup = countryCodeFromGeoLookup;     }     @Override     protected UserAccount getFallback() {         /**          * Return stubbed fallback with some static defaults, placeholders,          * and an injected value 'countryCodeFromGeoLookup' that we'll use          * instead of what we would have retrieved from the remote service.          */         return new UserAccount(customerId, "Unknown Name",                 countryCodeFromGeoLookup, true, true, false);     } 

5、Fallback: Cache via Network 利用远程缓存

通过远程缓存的方式。在失败的情况下再发起一次remote请求,不过这次请求的是一个缓存比如redis。由于是又发起一起远程调用,所以会重新封装一次Command,这个时候要注意,执行fallback的线程一定要跟主线程区分开,也就是重新命名一个ThreadPoolKey。

Cache via Network.png

Cache via Network.png

public class CommandWithFallbackViaNetwork extends HystrixCommand<String> {     private final int id;      protected CommandWithFallbackViaNetwork(int id) {         super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceX"))                 .andCommandKey(HystrixCommandKey.Factory.asKey("GetValueCommand")));         this.id = id;     }      @Override     protected String run() {         //        RemoteServiceXClient.getValue(id);         throw new RuntimeException("force failure for example");     }      @Override     protected String getFallback() {         return new FallbackViaNetwork(id).execute();     }      private static class FallbackViaNetwork extends HystrixCommand<String> {         private final int id;          public FallbackViaNetwork(int id) {             super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RemoteServiceX"))                     .andCommandKey(HystrixCommandKey.Factory.asKey("GetValueFallbackCommand"))                     // use a different threadpool for the fallback command                     // so saturating the RemoteServiceX pool won't prevent                     // fallbacks from executing                     .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("RemoteServiceXFallback")));             this.id = id;         }          @Override         protected String run() {             MemCacheClient.getValue(id);         }          @Override         protected String getFallback() {             // the fallback also failed             // so this fallback-of-a-fallback will              // fail silently and return null             return null;         }     } } 

6、Primary + Secondary with Fallback 主次方式回退(主要和次要)

这个有点类似我们日常开发中需要上线一个新功能,但为了防止新功能上线失败可以回退到老的代码,我们会做一个开关比如使用zookeeper做一个配置开关,可以动态切换到老代码功能。那么Hystrix它是使用通过一个配置来在两个command中进行切换。

Primary + Secondary with Fallback.png

Primary + Secondary with Fallback.png

/**  * Sample {@link HystrixCommand} pattern using a semaphore-isolated command  * that conditionally invokes thread-isolated commands.  */ public class CommandFacadeWithPrimarySecondary extends HystrixCommand<String> {      private final static DynamicBooleanProperty usePrimary = DynamicPropertyFactory.getInstance().getBooleanProperty("primarySecondary.usePrimary", true);      private final int id;      public CommandFacadeWithPrimarySecondary(int id) {         super(Setter                 .withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))                 .andCommandKey(HystrixCommandKey.Factory.asKey("PrimarySecondaryCommand"))                 .andCommandPropertiesDefaults(                         // we want to default to semaphore-isolation since this wraps                         // 2 others commands that are already thread isolated                         // 采用信号量的隔离方式                         HystrixCommandProperties.Setter()                                 .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));         this.id = id;     }      //通过DynamicPropertyFactory来路由到不同的command     @Override     protected String run() {         if (usePrimary.get()) {             return new PrimaryCommand(id).execute();         } else {             return new SecondaryCommand(id).execute();         }     }      @Override     protected String getFallback() {         return "static-fallback-" + id;     }      @Override     protected String getCacheKey() {         return String.valueOf(id);     }      private static class PrimaryCommand extends HystrixCommand<String> {          private final int id;          private PrimaryCommand(int id) {             super(Setter                     .withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))                     .andCommandKey(HystrixCommandKey.Factory.asKey("PrimaryCommand"))                     .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("PrimaryCommand"))                     .andCommandPropertiesDefaults(                             // we default to a 600ms timeout for primary                             HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(600)));             this.id = id;         }          @Override         protected String run() {             // perform expensive 'primary' service call             return "responseFromPrimary-" + id;         }      }      private static class SecondaryCommand extends HystrixCommand<String> {          private final int id;          private SecondaryCommand(int id) {             super(Setter                     .withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))                     .andCommandKey(HystrixCommandKey.Factory.asKey("SecondaryCommand"))                     .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("SecondaryCommand"))                     .andCommandPropertiesDefaults(                             // we default to a 100ms timeout for secondary                             HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100)));             this.id = id;         }          @Override         protected String run() {             // perform fast 'secondary' service call             return "responseFromSecondary-" + id;         }      }      public static class UnitTest {          @Test         public void testPrimary() {             HystrixRequestContext context = HystrixRequestContext.initializeContext();             try {                 //将属性"primarySecondary.usePrimary"设置为true,则走PrimaryCommand;设置为false,则走SecondaryCommand                 ConfigurationManager.getConfigInstance().setProperty("primarySecondary.usePrimary", true);                 assertEquals("responseFromPrimary-20", new CommandFacadeWithPrimarySecondary(20).execute());             } finally {                 context.shutdown();                 ConfigurationManager.getConfigInstance().clear();             }         }          @Test         public void testSecondary() {             HystrixRequestContext context = HystrixRequestContext.initializeContext();             try {                 //将属性"primarySecondary.usePrimary"设置为true,则走PrimaryCommand;设置为false,则走SecondaryCommand                 ConfigurationManager.getConfigInstance().setProperty("primarySecondary.usePrimary", false);                 assertEquals("responseFromSecondary-20", new CommandFacadeWithPrimarySecondary(20).execute());             } finally {                 context.shutdown();                 ConfigurationManager.getConfigInstance().clear();             }         }     } } 

三、总结

降级的处理方式,返回默认值,返回缓存里面的值(包括远程缓存比如redis和本地缓存比如jvmcache)。
但回退的处理方式也有不适合的场景:
1、写操作
2、批处理
3、计算
以上几种情况如果失败,则程序就要将错误返回给调用者。


转载请注明出处,并附上链接https://my.oschina.net/wangxindong/blog/1518994
参考资料:https://github.com/Netflix/Hystrix/wiki

本文发表于2017年08月23日 10:36
(c)注:本文转载自https://my.oschina.net/wangxindong/blog/1518994,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1826 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1