Hystrix的核心工作原理

Hystrix的本质作用是当系统资源过载(Over Load Control)时提供服务状态保护机制,包括下面四个方面。

● 熔断:当失败率达到阈值时自动触发降级(如因网络故障或超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。

● 隔离(线程池隔离和信号量隔离):限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他调用。

● 降级:超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据,做到优雅降级。

● 缓存:提供了请求缓存、请求合并的实现方法。

Hystrix——熔断

熔断器的原理很简单,可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器也可以使应用程序诊断错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。

熔断器就像是那些容易导致错误的操作的一种代理。这种代理能够记录最近调用发生错误的次数,然后决定允许操作继续或者立即返回错误。熔断器开关相互转换的逻辑如下图所示。

Hystrix中的熔断器(Circuit Breaker)也起到这样的作用,Hystrix在运行过程中会向每个CommandKey对应的熔断器报告成功、失败、超时和拒绝的状态,熔断器维护并计算统计的数据,根据这些统计信息来确定是否打开。如果打开,后续的请求都会被截断(不再执行run方法里的内容,直接执行fallback方法里的内容)。然后隔一段时间(默认是5s),尝试半开,放一部分请求进来,相当于对依赖服务进行一次健康检查,如果服务没问题,熔断器关闭,随后完全恢复调用。

Hystrix——隔离

对于微服务系统来说,一个从客户端发来的HTTP请求往往途径众多微服务,在处于高流量状态下,如果其中一个服务器资源出现饱和状态,就会影响上游系统。如下图所示,Hystrix可以将服务调用包裹在HystrixCommand中,每一个HystrixCommand都维护着一个线程池,从而隔离服务,当一个服务产生延迟时,其“吞噬”的资源也只会限定在该HystrixCommand内(比如至多只会占用N个线程资源),而不会对全局造成影响。

Hystrix的隔离主要是为每个依赖组件提供一个隔离的线程环境,有两种隔离模式。

● 线程池隔离模式:使用一个线程池来存储当前的请求。线程池对请求做处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池里慢慢处理)。

● 信号量隔离模式:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求到来时先判断计数器的数值,若超过设置的最大线程个数,则丢弃该类型的新请求,若不超过,则执行计数操作,请求到来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)。

两种隔离模式的主要区别如下表所示。

Hystrix隔离策略相关的参数如下。


execution.isolation.strategy=THREAD|SEMAPHORE:设置线程或信号量隔离模式。


hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:设置隔离模式的超时时间,默认值是1000ms。


execution.isolation.semaphore.maxConcurrentRequests :设置在使用时允许到HystrixCommand.run方法的最大请求数,默认值是10。

● execution.timeout.enabled:设置HystrixCommand.run方法执行时是否开启超时设置,默认开启。


execution.isolation.thread.interruptOnTimeout:发生超时时是否中断HystrixCommand.run方法,默认是true。


execution.isolation.thread.interruptOnCancel:取消时是否中断HystrixCommand.run方法,默认是false。

Hystrix——降级

所谓降级,就是指在Hystrix执行非核心链路功能失败的情况下,我们如何处理,比如我们返回默认值等。如果我们要回退或者降级处理 , 代 码 上 需 要 实 现
HystrixCommand.getFallback 方 法 或 者HystrixObservableCommand方法。

Netflix的Hystrix对微服务降级处理实现提供两种方式:

● 通过添加注解@HystrixCommand方式来实现。

● 通过继承HystrixCommand类来实现。

1.使用@HystrixCommand注解实现服务降级

使用注解可以最小限度地侵入代码,可以快速让原来的功能支持服 务 降 级 , 使 用 时 仅 需 在 要 进 行 服 务 降 级 处 理 的 方 法 上 增 加@HystrixCommand注解即可,并通过fallbackMethod属性设置在降级处理时所使用的方法,然后在降级方法中实现服务降级处理。需要注意:通过fallbackMethod属性所指定的方法要与原方法具有相同的方法签名,否则降级会失败。下面是@HystrixCommand的参数说明。

● groupKey:设置HystrixCommand分组的名称。

● commandKey:设置HystrixCommand的名称。

● threadPollKey:设置HystrixCommand执行线程池的名称。

● fallbackMethod:设置HystrixCommand服务降级所使用的方法

名称,注意该方法需要与原方法定义在同一个类中,并且方法签名也要一致。

● commandProperties:设置HystrixCommand属性,例如断路器失败百分比、断路器时间容器大小等。

● ignoreException:设置HystrixCommand执行服务降级处理时需要忽略的异常,当出现异常时不会执行服务降级处理。

● observableExecutionMode : 设 置 HystrixCommand 执 行 的 方式。

● defaultFallback:设置HystrixCommand默认的服务降级处理方 法 , 如 果 同 时 设 定 fallbackMethod 属 性 , 会 优 先 使 用fallbackMethod属性所指定的方法。该属性所指定的方法没有参数,需要注意返回值与原方法返回值的兼容性。

2.继承HystrixCommand类实现服务降级

除使用注解方式来完成服务降级实现外,Hystrix还提供了两个对象 来 支 持 服 务 降 级 实 现 处 理 : HystrixCommand 和HystrixObserableCommand 。 如 果 继 承 HystrixCommand 则 需 要 实 现getFallback方法,代码如下:

HystrixObserableCommand用于所依赖服务返回多个操作结果的时候,在实现服务降级时,如果是继承HystrixObserableCommand,则需要实现resumeWithFallback方法,代码如下。

Hystrix——缓存

Hystrix有两种方式来应对高并发场景,分别是请求缓存与请求合并缓存。请求缓存是在同一请求多次访问中保证只调用一次这个服务提供者的接口,同一请求第一次的结果会被缓存,保证同一请求多次访问返回结果相同。

Hystrix的缓存实现方式主要有两种:继承方式和注解方式,用得比较多的方式是注解方式,因为注解方式开发快而且相对简单,如下表所示。

1.使用@CacheResult开启请求缓存功能

2.使用CacheKey开启缓存

3.通过@CacheRemove注解来实现失效缓存清理功能

Hystrix的工作流程

Hystrix使用RxJava作为响应式的编程框架。这里我们简单介绍一下Hystrix的工作流程,一个简化版本的Hystrix执行流程如下图所示。

首先,构造一个HystrixCommand或HystrixObservableCommand对象。

● 如果期望依赖项返回单个响应,则构造一个HystrixCommand对象,代码如下:

● 如果期望依赖项返回发出响应的可观察对象,则构造一个HystrixObservableComman对象,代码如下:

有4种方法可以执行Hystrix命令(前两种方法只适用于简单的HystrixCommand对象,不适用于HystrixObservableCommand对象)。

● execute:该方法与queue方法以相同的方式获取一个Future对象,然后在这个Future上调用get方法来获取可观察对象发出的单个值。

● queue:该方法将可观察对象转换为BlockingObservable对象,以便将其转换为Future对象,然后返回此Future对象。

● observe:该方法可以立即订阅可观察对象,并开始执行命令的流。返回一个可观察对象,当订阅该对象时,它将重新产生结果并通知订阅者。

● toObservable:该方法返回的可观察值不变,需要订阅后才能真正开始执行命令流程。

下面是Hystrix的具体执行逻辑。

1.构造Hystrix命令

构造一个HystrixCommand或HystrixObservableCommand对象,用于封装请求并在构造方法中配置请求被执行需要的参数。

2.执行Hystrix命令

根据上文中提供的4种方式执行命令。

3.判断是否缓存了响应

如果你为命令启用了请求缓存,并且在缓存中命中了可用请求的响应,则缓存的响应将立即以可观察到的形式返回。

4.判断熔断电路是否打开

当执行命令时,Hystrix将与断路器一起检查熔断电路是否打开。

如果熔断电路打开,那么Hystrix将不执行命令并回退。如果熔断电路关闭,则继续执行,检查是否有可用的容量来运行命令。

5.线程池、队列、信号量是否已满

如果与命令关联的线程池和队列(或信号量,如果不在线程中运行)已满,那么Hystrix将不执行命令,执行逻辑跳转到第7步。

6.计算电路健康状态

执行
HystrixObservableCommand.construct或HystrixCommand.run方法,Hystrix向断路器报告成功、失败、拒绝或超时,如果执行逻辑失败或者超,则执行逻辑跳转第7步;否则执行逻辑跳转到第8步;

7.回退

Hystrix试图恢复你的回滚命令,并执行回退逻辑或者fallback备用逻辑。

8.返回成功的响应如果Hystrix命令成功,它将以可观察到的形式返回响应给调用者。