开篇
对Hystrix耳闻已久,最近刚好想在项目中使用这个神器就顺带研究了一把,很多细节来不及深入研究只能把宏观上的各个概念讲解一下,这个介绍的素材大都来自github上的Hystrix官网。
所谓一图胜千言,但凡能够用图片来表示而且能够表示清楚的,就不多用文字描述了,看图肯定比看文字要让人来的更爽一些。当然我还是非常建议去github上的Hystrix官方wiki去看原汁原味的文档,在参考文献部分已经给出了链接。
最后提一点,就是在Hystrix的实现当中大量使用了RxJava的开源包的技术,这个技术之前没怎么研究过,所以后面的很多源码的分析更多侧重过程分析而不会深入细节,有兴趣的可以自己深入研究下,我就准备哪天得空好好去研究一下,毕竟RxJava这个东西号称是一个通过使用可观察序列来编写异步和基于事件的程序的库。
Hystrix的设计理念
- Give protection from and control over latency and failure from dependencies accessed (typically over the network) via third-party client libraries.
给依赖于第三方库的应用程序提供给保护 - Stop cascading failures in a complex distributed system.
在复杂的分布式系统当中避免级联失败 - Fail fast and rapidly recover.
快速失败并且快速恢复 - Fallback and gracefully degrade when possible.
在可能的情况下提供回退和优雅降级的能力 - Enable near real-time monitoring, alerting, and operational control.
通过近乎实时的指标,监控和警报来优化发现故障的时间。
Hystrix提供的能力
hystrix的出现即为解决雪崩效应,它通过四个方面的机制来解决这个问题
- 隔离(线程池隔离和信号量隔离):限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
- 优雅的降级机制:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。
- 熔断:当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。
- 缓存:提供了请求缓存、请求合并实现。
- 支持实时监控、报警、控制
Hystrix-隔离
Hystrix的隔离主要是为每个依赖组件提供一个隔离的线程环境,提供两种模式的隔离:
- 线程池隔离模式:使用一个线程池来存储当前的请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池队里慢慢处理)
- 信号量隔离模式:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃改类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)
线程池隔离 | 信号量隔离 | |
---|---|---|
线程 | 与调用线程不相同线程 | 与调用线程相同 |
开销 | 排队、调度、上下文开销等 | 无线程切换,开销低 |
异步 | 支持 | 不支持 |
并发支持 | 支持(最大线程池大小) | 支持(最大信号量上限) |
Hystrix-熔断器
Hystrix的熔断器其实可以理解为就是一个统计中心,统计一定时间窗口内访问次数,成功次数,失败次数等数值判定是否发生熔断。发生电路熔断的过程如下:
- 假设电路上的音量达到一定阈值(HystrixCommandProperties.circuitBreakerRequestVolumeThreshold)
- 并假设错误百分比超过阈值错误百分比(HystrixCommandProperties.circuitBreakerErrorThresholdPercentage)
- 然后断路器从CLOSED转换到OPEN。
- 它是开放的,它使所有针对该断路器的请求短路。
- 经过一段时间(HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds),下一个单个请求是通过(这是HALF-OPEN状态)。 如果请求失败,断路器将在睡眠窗口持续时间内返回到OPEN状态。 如果请求成功,断路器将转换到CLOSED,逻辑1.重新接管。
Hystrix工作流程
- 构建一个HystrixCommand或者HystrixObservableCommand 对象。
- 执行Command
- 响应是否有缓存?如果为该命令启用请求缓存,并且如果缓存中对该请求的响应可用,则此缓存响应将立即以“可观察”的形式返回。
- 熔断器是否打开?如果电路打开(或“跳闸”),则Hystrix将不会执行该命令,但会将流程路由到(8)获取回退。如果电路关闭,则流程进行到(5)以检查是否有可用于运行命令的容量。
- 线程池/队列/信号量是否已经满负载?如果与命令相关联的线程池和队列(或信号量,如果不在线程中运行)已满,则Hystrix将不会执行该命令,但将立即将流程路由到(8)获取回退。
- 执行真正的命令部分,HystrixObservableCommand.construct() 或者 HystrixCommand.run(),在这里Hystrix通过您为此目的编写的方法调用对依赖关系的请求。如果run或construct方法超出了命令的超时值,则该线程将抛出一个TimeoutException, 在这种情况下,Hystrix将响应通过8进行路由。获取Fallback,如果该方法不取消/中断,它会丢弃最终返回值run()或construct()方法。
- 计算Circuit 的健康,Hystrix向断路器报告成功,失败,拒绝和超时,该断路器维护了一系列的计算统计数据组。它使用这些统计信息来确定电路何时“跳闸”,此时短路任何后续请求直到恢复时间过去,在首次检查某些健康检查之后,它再次关闭电路。
- 获取Fallback,当命令执行失败时,Hystrix试图恢复到你的回退:当construct或run抛出异常时[6],当命令由于电路断开而短路时[4],当命令的线程池和队列或信号量处于容量[5],或者当命令超过其超时长度时[6]。
- 返回成功的响应,如果 Hystrix command成功,如果Hystrix命令成功,它将以Observable的形式返回对呼叫者的响应或响应。