Hystrix 工作流程
Hystrix是如何处理请求,在官网有详细介绍:https://github.com/Netflix/Hystrix/wiki/How-it-Works, 本文重点围绕下方流程图介绍一下主要的流程;
Hystrix是将我们的系统间调用包装成一个个Comman来执行,举个简单的例子:
public class TestCommand extends HystrixCommand<Integer> { private TestServiceA serviceA; private int index; private static HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter() //至少有10个请求,熔断器才进行错误率的计算 .withCircuitBreakerRequestVolumeThreshold(3) //熔断器中断请求5秒后会进入半打开状态,放部分流量过去重试 .withCircuitBreakerSleepWindowInMilliseconds(5000) //错误率达到50开启熔断保护 // .withCircuitBreakerErrorThresholdPercentage(30) .withExecutionIsolationSemaphoreMaxConcurrentRequests(2) .withExecutionTimeoutEnabled(true) .withExecutionTimeoutInMilliseconds(1000); protected TestCommand(TestServiceA serviceA, int index) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("testGroupKey")) .andCommandKey(HystrixCommandKey.Factory.asKey("testCommandKey")) .andCommandPropertiesDefaults(setter) .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(10))); this.serviceA = serviceA; this.index = index; } @Override protected Integer run() throws Exception { return serviceA.service(index); } @Override protected Integer getFallback() { // if service execute fail, do sth return -1; } }
// execute
TestCommand testCommand = new TestCommand(new TestServiceA(), i);
testCommand.execute();
我们只需要用一个Command来包装我们的RPC/RMI调用,上面就使用 TestCommand 包装了一个TestService 方法;
下面解释流程图中具体逻辑;
1、包装请求:
可以使用继承HystrixCommand或HystrixObservableCommand来包装业务方法;
2、发起请求:
使用调用Command的execute来执行一个业务方法调用;
Hystrix除了提供了execute方法,另外还提供了3种方来,所有的请求入口:
K value = command.execute(); Future<K> fValue = command.queue(); Observable<K> ohValue = command.observe(); //hot observable Observable<K> ocValue = command.toObservable(); //cold observable
如上图所示:
执行同步调用execute方法,会调用queue().get()方法,queue()又会调用toObservable().toBlocking().toFuture();
所以,所有的方法调用都依赖Observable的方法调用,只是取决于是需要同步还是异步调用;
3、缓存处理:
当请求来到后,会判断请求是否启用了缓存(默认是启用的),再判断当前请求是否携带了缓存Key;
如果命中缓存就直接返回;否则进入剩下的逻辑;
4、判断断路器是否打开(熔断):
断路器是Hystrix的设计核心,断路器是实现快速失败的重要手段(断路器打开就直接返回失败);
可以设置断路器打开一定时间后,可以进行尝试进行业务请求(默认是5000毫秒);
5、判断是否进行业务请求(请求是否需要隔离或降级):
是否进行业务请求之前还会根据当前服务处理质量,判断是否需要去请求业务服务;
如果当前服务质量较低(线程池/队列/信号量已满),那么也会直接失败;
线程池或信号量的选择(默认是线程池):
线程池主要优势是客户端隔离和超时设置,但是如果是海量低延迟请求时,频繁的线程切换带来的损耗也是很可观的,这种情况我们就可以使用信号量的策略;
信号量的主要缺点就是不能处理超时,请求发送到客户端后,如果被客户端pending住,那么就需要一直等待;
6、执行业务请求:
当前服务质量较好,那么就会提交请求到业务服务器去;
HystrixObservableCommand.construct()
or HystrixCommand.run()
7、健康监测:
根据历史的业务方法执行结果,来统计当前的服务健康指标,为断路器是否熔断等动作作为依据;
8/9、响应失败或成功的处理结果