博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Hystrix降级技术解析-Fallback
阅读量:7047 次
发布时间:2019-06-28

本文共 9597 字,大约阅读时间需要 31 分钟。

hot3.png

一、降级

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

public class CommandHelloFailure extends HystrixCommand
{ 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
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
getFallback() { return Collections.emptyList(); }@Override protected Observable
resumeWithFallback() { return Observable.empty(); }

3、Fallback: Static 返回默认值

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

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

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

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

public class CommandWithStubbedFallback extends HystrixCommand
{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
{ 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
{ 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
{ 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
{ 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
{ 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

你可能感兴趣的文章
ios 导航问题
查看>>
[Android学习笔记]使用getIdentifier()获取资源Id
查看>>
SQL 视图
查看>>
笔试题:爱情数字
查看>>
ADO.NET程序访问数据的组件
查看>>
Vim与Python真乃天作之合
查看>>
阅读《移山之道》及讲义感想
查看>>
css3实现好看的边框效果
查看>>
Difference Between 2 Dates or 2 Times
查看>>
python练习-简单小爬虫
查看>>
python进阶-面向对象编程五:类的内置方法
查看>>
JAVA入门到精通-第52讲-面试题讲评
查看>>
springboot的热部署和dubug
查看>>
Nest.js 守卫
查看>>
再说rocketmq消息存储
查看>>
16年国庆假期期间兼职所悟
查看>>
javaWeb服务详解【客户端调用】(含源代码,测试通过,注释) ——Emp实体类...
查看>>
Spring知识点
查看>>
PHP中array
查看>>
Android经典应用软件大全
查看>>