Hystrix系列之信号量、线程池

Hystrix内部提供了两种模式执行逻辑:信号量、线程池。

Hystrix系列之信号量、线程池_第1张图片
来自hystrix官网

默认情况下,Hystrix使用线程池模式。
不过两者有什么区别,在实际场景中如何选择?

Hystrix系列之信号量、线程池_第2张图片

如果要使用信号量模式,需要配置参数execution.isolation.strategy = ExecutionIsolationStrategy.SEMAPHORE.

信号量模式

在该模式下,接收请求和执行下游依赖在同一个线程内完成,不存在线程上下文切换所带来的性能开销,所以大部分场景应该选择信号量模式,但是在下面这种情况下,信号量模式并非是一个好的选择。

比如一个接口中依赖了3个下游:serviceA、serviceB、serviceC,且这3个服务返回的数据互相不依赖,这种情况下如果针对A、B、C的熔断降级使用信号量模式,那么接口耗时就等于请求A、B、C服务耗时的总和,无疑这不是好的方案。

另外,为了限制对下游依赖的并发调用量,可以配置Hystrix的execution.isolation.semaphore.maxConcurrentRequests,当并发请求数达到阈值时,请求线程可以快速失败,执行降级。

Hystrix系列之信号量、线程池_第3张图片

实现也很简单,一个简单的计数器,当请求进入熔断器时,执行tryAcquire(),计数器加1,结果大于阈值的话,就返回false,发生信号量拒绝事件,执行降级逻辑。当请求离开熔断器时,执行release(),计数器减1。

线程池模式

在该模式下,用户请求会被提交到各自的线程池中执行,把执行每个下游服务的线程分离,从而达到资源隔离的作用。当线程池来不及处理并且请求队列塞满时,新进来的请求将快速失败,可以避免依赖问题扩散。

在信号量模式提到的问题,对所依赖的多个下游服务,通过线程池的异步执行,可以有效的提高接口性能。

优势

  • 减少所依赖服务发生故障时的影响面,比如ServiceA服务发生异常,导致请求大量超时,对应的线程池被打满,这时并不影响ServiceB、ServiceC的调用。
  • 如果接口性能有变动,可以方便的动态调整线程池的参数或者是超时时间,前提是Hystrix参数实现了动态调整。

缺点

  • 请求在线程池中执行,肯定会带来任务调度、排队和上下文切换带来的开销。
  • 因为涉及到跨线程,那么就存在ThreadLocal数据的传递问题,比如在主线程初始化的ThreadLocal变量,在线程池线程中无法获取

注意

因为Hystrix默认使用了线程池模式,所以对于每个Command,在初始化的时候,会创建一个对应的线程池,如果项目中需要进行降级的接口非常多,比如有上百个的话,不太了解Hystrix内部机制的同学,按照默认配置直接使用,可能就会造成线程资源的大量浪费。

你可能感兴趣的:(Hystrix系列之信号量、线程池)