一、Hystrix的整体流程
1、构造HystrixCommand或HystrixObservableCommand对象
HystrixCommand command = new HystrixCommand(arg1, arg2);
HystrixObservableCommand command = new HystrixObservableCommand(arg1, arg2);
2、执行Command
hystrix命令执行最终都是调用的toObservable方法,后面我们再解析
// 同步
K value = command.execute();
// 异步
Future<K> fValue = command.queue();
// 异步调用,获取Observable
Observable<K> ohValue = command.observe(); //hot observable
// 调用toObservable会立即执行hystrix命令
Observable<K> ocValue = command.toObservable(); //cold observable
3、是否命中缓存
当request cache开启并且命中缓存逻辑,那么就会直接返回结果
4、断路器是否打开状态
判断当前是否出发熔断 触发熔断就会获取fallback信息返回,否则往下处理
5、线程池/队列/信号量是否已经满了?
判断线程池、队列状态,如果满了就会走到fallback逻辑
6、执行command的构造函数或者运行command
7、计算断路器的健康状况
根据hystrix记录的成功、失败、拒绝、超时等信息,判断当前是否熔断 触发熔断就不会处理任何请求直到超过恢复间隔
8、获取fallback信息
用来做熔断、失败等异常处理的,这个很重要
9、返回正确的结果
二、断路器
断路器的逻辑:
- 当qps(HystrixCommandProperties.circuitBreakerRequestVolumeThreshold())或者错误占比(HystrixCommandProperties.circuitBreakerErrorThresholdPercentage())达到一定的阈值就会将断路器的开关状态从CLOSE置为OPEN
- 当超过休眠时间(HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds())之后,此时断路器状态为半开状态,如果下一个请求还是失败那么断路器就会变成开启状态,成功就会切换成CLOSE状态
1、断路器的计算规则?
- 断路器是通过滚动窗口(默认10s)来计算是否触发开关开启
- 每个窗口会有多个bucket(默认10个),bucket中存放当前桶所在时间段(比如1s一个桶)错误数量、成功数量、超时、拒绝的数据量,这样可以计算错误占比、总请求量
- 另外99th的计算也是通过滚动窗口(默认60s)+bucket来实现,记录每个请求的耗时,但是可以设置桶的数量和每个桶最多存放的样本数量
三、隔离
- hystrix采用舱壁模式将服务和它的依赖隔离开,并且限制每一个服务的并发
- hystrix隔离有线程池和信号量两个实现方式
1、线程池
- 线程池是hystrix使用的一种隔离方式
- 它是将服务的每个依赖作为一个线程池来进行隔离
2、信号量semaphore
1、在fallback场景执行 2、在执行时用来限制并发量的场景 3、由于semaphore的特性,当所有线程处于阻塞时那么就不能接受请求,除非超时
四、请求合并
- 所谓请求合并,就是将用户对于某个依赖的多个请求合并成一次请求,减少线程创建以及连接创建的开销,具体如下图
- 请求合并分为全局级别和requestcontext级别
1、请求合并的流程图
- 请求合并中bacth请求发送周期是10ms一次,每隔10ms就会从RequestQueue中拉去当前的队列数据进行合并发送
- 请求折叠是自动完成的,这里面包含一些batch reponse的处理
五、请求缓存
- 避免HystixCommand去做重复的工作
- 不同hystrixCommand的执行方式都是可以命中缓存的,比如execute和queue等