blog

Spring Cloud中hystrix两种隔离策略

hystrix有两种隔离策略:THREAD和SEMAPHORE(参见ExecutionIsolationStrategy),默认为THREAD(具体配置在Spring Cloud文档中没有说明,需要参见HystrixCommandProperties)。

两者解释如下:

在Spring Cloud的文档中说明的是,在Feign中,如果需要在RequestInterceptor中使用ThreadLocal 绑定变量,则必须设置线程隔离策略为SEMAPHORE,或者禁用Hystrix。

明白了两种隔离策略就明白为什么官网上要这样说明了,其实就是因为使用THREAD的隔离策略会导致在一个新的线程池上执行,而不同线程之间是无法传递ThreadLocal 绑定的变量的。

在网上查了一下,发现是可以解决这个问题的,参见 Spring Cloud中Hystrix 线程隔离导致ThreadLocal数据丢失(上)Spring Cloud中Hystrix 线程隔离导致ThreadLocal数据丢失(下)

以下是对这两篇文章的大概总结。

ThreadLocal 只能在线程中保存变量,但如果需要在线程之间传递线程中ThreadLocal 保存的变量,可以使用InheritableThreadLocal来保存变量。它们两个的基本原理都是在Thread中有相应的变量threadLocalsinheritableThreadLocals,设置了相应的数据后,就会被保存到相应的变量中,而在新线程创建时,原线程中inheritableThreadLocals保存的变量就会被复制到新线程中。

使用inheritableThreadLocal有一个问题就是它是在新建线程的时候才会被赋值,对于线程池的情况就无能为力了。但是还有另外的解决方案,那就是transmittable-thread-local,它解决的问题就是跨线程传递数据。

现在的问题就是改造hystrix,让它使用transmittable-thread-local来创建线程。

这篇文章中给出了两种解决方案,但第一种方法写得比较模糊,也许是太简单了就一笔带过吧。

其实查了一下hystrix的官网,发现hystrix有plugins的概念,其中plugin的类型就有并发策略,具体可以参考官方文档 hystrix plugins

官方文档上面说,可以实现HystrixConcurrencyStrategy 类来替换默认的并发策略。

查看HystrixConcurrencyStrategy类,发现有两个实现类,自己默认的实现类HystrixConcurrencyStrategyDefault以及Spring Cloud的实现类SecurityContextConcurrencyStrategy,而SecurityContextConcurrencyStrategy只是包装了HystrixConcurrencyStrategy类,并没有做其它的事情。再看SecurityContextConcurrencyStrategy所在的包,发现同一个包下还有一个类HystrixSecurityAutoConfiguration,在这个类里,配置了使用SecurityContextConcurrencyStrategy的场景。