HYSTRIX实现主线程和子线程的THREADLOCAL上下文传递
問題描述
我在使用日志鏈路追蹤的時候(基于SLF4J MDC機制實現(xiàn)日志的鏈路追蹤),我發(fā)現(xiàn)使用Hystrix線程池隔離的時候,我不能將子線程沒有復制主線程的MDC上下文(Slf4j MDC機制
),導致日志鏈路斷掉。
問題分析
Hystrix的線程池隔離是使用HystrixThreadPool來實現(xiàn)的。而獲取HystrixThreadPool是在HystrixConcurrencyStrategy。在這里我們可以看到類的描述:
Abstract class for defining different behavior or implementations for concurrency related aspects of the system with default implementations.
For example, every Callable executed by HystrixCommand will call wrapCallable(Callable) to give a chance for custom implementations to decorate the Callable with additional behavior.
When you implement a concrete HystrixConcurrencyStrategy, you should make the strategy idempotent w.r.t ThreadLocals. Since the usage of threads by Hystrix is internal, Hystrix does not attempt to apply the strategy in an idempotent way. Instead, you should write your strategy to work idempotently. See Timeout handling fails for non-idempotent strategy · Issue #351 · Netflix/Hystrix · GitHub for a more detailed discussion.
See HystrixPlugins or the Hystrix GitHub Wiki for information on configuring plugins: Plugins · Netflix/Hystrix Wiki · GitHub.
大致意思是HystrixConcurrencyStrategy提供了一套默認的并發(fā)策略實現(xiàn)。我們可以根據(jù)我們自己不同需求通過裝飾去擴展它。如每次執(zhí)行HystrixCommand的時候都會去調(diào)用wrapCallable(Callable) 方法,這里我們就可以通過裝飾Callable使它提供一些額外的功能(如ThreadLocal上下文傳遞)。還附上了插件的文檔:Plugins · Netflix/Hystrix Wiki · GitHub。
打開文檔,將會教我們?nèi)绾稳U展HystrixConcurrencyStrategy并使它生效。
實現(xiàn)
擴展HystrixConcurrencyStrategy
/*** Hystrix線程池隔離支持日志鏈路跟蹤** @author yuhao.wang3*/ public class MdcHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {@Overridepublic <T> Callable<T> wrapCallable(Callable<T> callable) {return new MdcAwareCallable(callable, MDC.getCopyOfContextMap());}private class MdcAwareCallable<T> implements Callable<T> {private final Callable<T> delegate;private final Map<String, String> contextMap;//具體怎么定義這個方法,你可以啟動在這里打斷點,看看你的線程中有些什么必須要有的東西public MdcAwareCallable(Callable<T> callable, Map<String, String> contextMap) {this.delegate = callable;this.contextMap = contextMap != null ? contextMap : new HashMap();}@Overridepublic T call() throws Exception {try {MDC.setContextMap(contextMap);return delegate.call();} finally {MDC.clear();}}} }通過裝飾Callable類,我們在MdcAwareCallable#call()方法中先將MDC上下文復制到子線程。
注冊插件
@Configuration public class HystrixConfig {//用來攔截處理HystrixCommand注解@Beanpublic HystrixCommandAspect hystrixAspect() {return new HystrixCommandAspect();}@PostConstructpublic void init() {HystrixPlugins.getInstance().registerConcurrencyStrategy(new MdcHystrixConcurrencyStrategy());}}參考: https://github.com/Netflix/Hystrix/wiki/Plugins#concurrencystrategy
源碼
https://github.com/wyh-spring-ecosystem-student/spring-boot-student/tree/releases
總結
以上是生活随笔為你收集整理的HYSTRIX实现主线程和子线程的THREADLOCAL上下文传递的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用R语言绘制层次聚类热图
- 下一篇: Session一致性的解决方案