Hystrix是什么
Hystrix是Netflix开源的一款针对分布式系统的延迟和容错库,目的是用来隔离分布式服务故障,它提供线程和信号量隔离,以减少服务之间资源竞争带来的相互影响;提供优雅的降级机制;提供熔断机制使得服务可以快速失败,而不是一直阻塞等待服务响应,并能从中快速恢复。Hystrix通过这些机制来阻止级联失败并保证系统弹性、可用。
图-典型的分布式服务实现
在如上图典型的分布式服务中,多个Http服务会共享一个线程池,假设一个Http服务访问的数据库响应非常慢,这将会造成服务响应时间非常慢,大多数线程阻塞等待数据响应返回,导致整个Tomcat线程池都被该服务占用,甚至拖垮整个Tomcat,因此如果我们能把不同Http服务隔离到不同的线程池,则某个Http服务的线程池满了也不会对其它服务造成灾难性故障,这就需要线程隔离或者信号量隔离来实现了。使用线程隔离或者信号隔离的目的是为不同的服务分配一定的资源,当自己的资源用完,直接返回失败而不是占用别人的资源。同时我们依赖的服务访问超时时,要提供降级策略,比如返回托底策略阻止级联故障,当因为一些故障使得服务可用率下降时,要能及时熔断,一是快速失败,而是可以保护远程分布式服务。
Hystrix能做什么
限制调用布式服务的资源使用,通过线程池隔离和信号量隔离实现;
提供优雅的降级策略:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据;
提供熔断器实现,当失败率达到阈值自动触发降级,熔断器触发的快速失败会进行快速恢复;
提供请求缓存、请求合并实现。
线程隔离
Hystrix通过命令模式,将每个类型的业务请求封装成对应的命令请求。在应用Hystrix时,首先需要把服务封装成HystrixCommand,即命令模式实现,然后就可以通过同步/异步/响应式模式来调用服务。
执行依赖代码的线程与请求线程(比如Tomcat线程)分离,请求线程可以自由控制离开的时间,这也是我们通常说的异步编程,Hystrix是结合RxJava来实现的异步编程。通过设置线程池大小来控制并发访问量,当线程饱和的时候可以拒绝服务,防止依赖问题扩散。
图-隔离示例
信号量隔离只是限制了总的并发数,服务使用主线程进行同步调用,即没有线程池,因此如果只是限制某个服务的总并发调用量或者调用的服务不涉及远程调用的话,可以使用轻量级的信号量来实现。下面这张图说明了线程池隔离和信号量隔离的主要区别:线程池方式下业务请求线程和执行依赖的服务的线程不是同一个线程;信号量方式下业务请求线程和执行依赖服务的线程是同一个线程。
熔断器(Circuit Breaker)
Hystrix在运行过程中会向每个commandKey对应的熔断器报告成功、失败、超时和拒绝的状态,熔断器维护计算统计的数据,根据这些统计的信息来确定熔断器是否打开。如果打开,后续的请求都会被截断。然后会隔一段时间默认是5s,尝试半开,放入一部分流量请求进来,相当于对依赖服务进行一次健康检查,如果恢复,熔断器关闭,随后完全恢复调用,如下图所示。熔断后会自动降级处理。
回退降级
所谓降级,就是指在在Hystrix执行非核心链路功能失败的情况下,我们如何处理,比如我们返回默认值等 。降级的最终目的是保证核心服务可用,即使是有损的,而且有的服务是无法降级的(如加入购物车、结算),这时程序就要将错误返回给调用者。
结果cache
hystrix支持将一个请求结果缓存起来,下一个具有相同key的请求将直接从缓存中取出结果,减少请求开销。要使用hystrix cache功能,第一个要求是重写getCacheKey()
,用来构造cache key;第二个要求是构建context,如果请求B要用到请求A的结果缓存,A和B必须同处一个context。通过HystrixRequestContext.initializeContext()
和context.shutdown()
可以构建一个context,这两条语句间的所有请求都处于同一个context。
合并请求collapsing
Hystrix支持N个请求自动合并为一个请求,这个功能在有网络交互的场景下尤其有用,比如每个请求都要网络访问远程资源,如果把请求合并为一个,将使多次网络交互变成一次,极大节省开销。重要一点,两个请求能自动合并的前提是两者足够“近”,即两者启动执行的间隔时长要足够小,默认为10ms,即超过10ms将不自动合并。
参考链接
https://www.jianshu.com/p/3e11ac385c73
https://www.jianshu.com/p/b9af028efebb