Netflix 在 2012 年开源了熔断降级组件 Hystrix。Hystrix 促进了微服务“熔断降级”理念的推广,把隔离和熔断的理念传播到了广大的开发者当中。
长期以来,只要一说到隔离和熔断降级,开发者都会首先想到 Hystrix。到了 2014 年,Netflix 全面进军 Spring Cloud,Netflix 的一系列微服务组件也随着 Spring Cloud Netflix 纷至沓来,进入到开发者的视野中;同时,Hystrix 做了一次重大的重构,将底层的统计结构用 rxjava 重构,全面拥抱了 rxjava。长期以来,Hystrix 一直是业界熔断降级库的热门选择,但其社区活跃度一直在下降;最后,Hystrix 宣布停止维护。
支持功能
Hystrix 支持如下功能:
- 隔离机制:支持两种策略,线程池隔离(默认策略)和信号量隔离。
- 熔断降级机制:基于异常比率的策略。
- 限流机制:继承隔离机制的手段,使用线程池和信号量方式。
- 动态规则配置:支持多种数据源。
- 实时统计:基于 RxJava 的滑动窗口。
除以上之外,它还具有插件的形式扩展性、基于注解的支持及简单的监控查看等。
隔离机制
Hystrix 中非常核心的功能之一就是资源隔离,其要解决的主要问题,就是将多个服务的依赖调用分别隔离到各自的资源池内,以避免某个服务的大量调用或超时、失败等导致服务的全部的资源耗费,最终造成整个 service 的崩溃,甚至蔓延到其他服务,进而发生雪崩。
Hystrix 的隔离机制主要使用如下两种技术手段:
- 线程池
- 信号量
默认情况下,Hystrix 采用线程池的隔离策略。
线程池
Hystrix 采用了 Bulkhead Partition 舱壁隔离技术,来将外部依赖进行资源隔离,进而避免任何外部依赖的故障导致本服务崩溃。
舱壁隔离,指的是说将船体内部空间区隔划分成若干个隔舱,一旦某几个隔舱发生破损进水,水流不会在其间相互流动,如此一来船舶在受损时,依然能具有足够的浮力和稳定性,进而减低立即沉船的危险。
这里的隔舱在 Hystrix 里就是一个线程池,对每个外部依赖用一个独立的线程池,这样,如果对那个外部依赖调用消耗资源很严重,最多就是耗尽那个依赖自己的线程池而已,不会影响其他的依赖调用,本质上是给提供的服务设置资源上限。
线程池的隔离机制也存在着一些缺点,如它额外增加的 CPU 的开销,具体如下:
- 除了 tomcat 本身的线程池外,Hystrix 自己也管理着线程池,增加了资源的开销。
- 由于额外线程池的使用,相应的上下文切换的 CPU 开销。
信号量
信号量的资源隔离只是起到一个开关的作用,举例,一个服务 A 的信号量大小为 10(相当于给了 10 个许可证),那就是说它同时只允许有 10 个 tomcat 线程来访问服务 A,其它的请求都会被拒绝,从而达到资源隔离和限流保护的作用。
Sempahore 技术可以用来限流和削峰,但是不能用来对调用延迟的服务进行 timeout 的隔离。
如果通过信号量调用的时候,若底层的网络调用延迟很严重,那么是无法 timeout 的,只能一直 block 住。一旦请求数量超过了 semephore 限定的数量之后,就会立即开启限流。
线程池与信号量区别
线程池隔离技术,并不是控制类似 tomcat 这种 web 容器级别的线程。严格意义来讲,它控制的是 tomcat 线程的执行。Hystrix 线程池满后,会确保说,tomcat 的线程不会因为依赖服务的接口调用延迟或故障从而被 hang 住,tomcat 其它的线程也不会卡死,可以快速返回,然后去做其它的事情。
线程池隔离技术,是用 Hystrix 自己的线程去执行调用;而信号量隔离技术,是直接让 tomcat 线程去调用依赖服务。信号量隔离,只是一道关卡,信号量有多少,就允许多少个 tomcat 线程通过它,然后去执行。
如下图,清晰地描述了两者的显著区别:
限流
具体配置参见 Spring Cloud Hystrix 限流配置及实战示例。