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