一,hystrix整体流程

image.png

  1. 构造一个 HystrixCommand或HystrixObservableCommand对象,用于封装请求,并在构造方法中配置请求被执行需要的参数;
  2. 执行命令,Hystrix提供了4种执行命令的方法
  3. 判断是否使用缓存响应请求,若启用了缓存,且缓存可用,直接使用缓存响应请求。Hystrix支持请求缓存,但需要用户自定义启动;
  4. 判断熔断器是否打开,如果打开,执行第8步;
  5. 判断线程池/队列/信号量是否已满,已满则执行第8步;
  6. 执行HystrixObservableCommand.construct()或HystrixCommand.run(),如果执行失败或者超时,执行第8步;否则,跳到第9步;
  7. 统计熔断器监控指标;
  8. 走Fallback备用逻辑
  9. 返回请求响应

注意:1.第5步线程池/队列/信号量已满时,还会执行第7步逻辑,更新熔断器统计信息,而第6步无论成功与否,都会更新熔断器统计信息。2.可以通过重载getCacheKey()方法来开启请求缓存。如果涉及到数据修改则需要在修改的进修清除缓存,通过HystrixRequestCache.clear方法清除。

hystrxi设计理念

  • 使用命令模式将所有对外部服务(或依赖关系)的调用包装在HystrixCommand或HystrixObservableCommand对象中,并将该对象放在单独的线程中执行;
  • 每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)。
  • 记录请求成功,失败,超时和线程拒绝。
  • 服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求。
  • 请求失败,被拒绝,超时或熔断时执行降级逻辑。
  • 近实时地监控指标和配置的修改。

二,hystrix容错

一,资源隔离

资源隔离主要指对线程的隔离。Hystrix提供了两种线程隔离方式:线程池和信号量,默认为线程池。
使用线程池时,发送请求的线程和执行依赖服务的线程不是同一个;而使用信号量时,发送请求的线程和执行依赖服务的线程是同一个,都是发起请求的线程。

线程切换支持异步支持超时支持熔断限流开销
信号量
线程池

线程池和信号量都支持熔断和限流。
相比线程池,信号量不需要线程切换,如果是tomcat服务,那信号量使用的就是tomcat的线程而线程池则是tomcat线程创建的线程池,因此避免了不必要的开销。
但是信号量不支持异步,也不支持超时,也就是说当所请求的服务不可用时,信号量会控制超过限制的请求立即返回,但是已经持有信号量的线程只能等待服务响应或从超时中返回,即可能出现长时间等待。线程池模式下,当超过指定时间未响应的服务,Hystrix会通过响应中断的方式通知线程立即结束并返回。

基于上面两者的特点,我们可以知道它们分别适用的场景:

  • 信号量 请求并发大且耗时短(本服务的内存操作等);不会访问依赖外部的服务,因为信号量是不支持超时的,它处理不了timeout的问题
  • 线程池 请求并发大且耗时长;因为线程池是支持超时的,所以访问的服务是否依赖外部都行;如果应用恰好适合异步执行那线程池会是一个不错的选择。当然线程池也是需要维护的所以线程上下文切换也会有开销

二,熔断

熔断器里6个重要的参数:

  1. circuitBreaker.enabled
    是否启用熔断器,默认是TRUE。
  2. circuitBreaker.forceOpen
    熔断器强制打开,始终保持打开状态,不关注熔断开关的实际状态。默认值FLASE。
  3. circuitBreaker.forceClosed
    熔断器强制关闭,始终保持关闭状态,不关注熔断开关的实际状态。默认值FLASE。
  4. circuitBreaker.errorThresholdPercentage
    错误率,默认值50%,例如一段时间(10s)内有100个请求,其中有54个超时或者异常,那么这段时间内的错误率是54%,大于了默认值50%,这种情况下会触发熔断器打开。
  5. circuitBreaker.requestVolumeThreshold
    默认值20。含义是一段时间内至少有20个请求才进行errorThresholdPercentage计算。比如一段时间了有19个请求,且这些请求全部失败了,错误率是100%,但熔断器不会打开,总请求数不满足20。
  6. circuitBreaker.sleepWindowInMilliseconds
    半开状态试探睡眠时间,默认值5000ms。如:当熔断器开启5000ms之后,会尝试放过去一部分流量进行试探,确定依赖服务是否恢复。

断路开启,也就是由 close 转换到 open 状态(close -> open)。那么之后在 SleepWindowInMilliseconds 时间内(默认值5000ms),所有经过该断路器的请求全部都会被断路,不调用后端服务,直接走 fallback 降级机制。

而在该参数时间过后,断路器会变为 half-open 半开闭状态,尝试让一条请求经过断路器,看能不能正常调用。如果调用成功了,那么就自动恢复,断路器转为 close 状态。

三,降级

降级,通常指务高峰期,为了保证核心服务正常运行,需要停掉一些不太重要的业务,或者某些服务不可用时,执行备用逻辑从故障服务中快速失败或快速返回,以保障主体业务不受影响。Hystrix提供的降级主要是为了容错,保证当前服务不受依赖服务故障的影响,从而提高服务的健壮性。要支持回退或降级处理,可以重写HystrixCommand的getFallBack方法或HystrixObservableCommand的resumeWithFallback方法。

Hystrix在以下几种情况下会走降级逻辑:

  • 执行construct()或run()抛出异常
  • 熔断器打开导致命令短路
  • 命令的线程池和队列或信号量的容量超额,命令被拒绝
  • 命令执行超时

降级回退方式有多种,这里列举两种:

  • 快速失败,快速失败是最普通的命令执行方法,命令没有重写降级逻辑。 如果命令执行发生任何类型的故障,它将直接抛出异常。
  • 无声失败,指在降级方法中通过返回null,空Map,空List或其他类似的响应来完成。

我们可以根据自己的业务需要开发降级方案,但是需要注意下降级逻辑是否会出异常的可能。

参考的文章:
深入 Hystrix 断路器执行原理
深入 Hystrix 线程池隔离与接口限流
Hystrix原理与实战


步履不停
38 声望13 粉丝

好走的都是下坡路