HYSTRIX实现主线程和子线程的THREADLOCAL上下文传递

87 篇文章 4 订阅
19 篇文章 2 订阅

问题描述

我在使用日志链路追踪的时候(基于SLF4J MDC机制实现日志的链路追踪),我发现使用Hystrix线程池隔离的时候,我不能将子线程没有复制主线程的MDC上下文(Slf4j MDC机制
),导致日志链路断掉。

问题分析

Hystrix的线程池隔离是使用HystrixThreadPool来实现的。而获取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提供了一套默认的并发策略实现。我们可以根据我们自己不同需求通过装饰去扩展它。如每次执行HystrixCommand的时候都会去调用wrapCallable(Callable) 方法,这里我们就可以通过装饰Callable使它提供一些额外的功能(如ThreadLocal上下文传递)。还附上了插件的文档:Plugins · Netflix/Hystrix Wiki · GitHub

打开文档,将会教我们如何去扩展HystrixConcurrencyStrategy并使它生效。

实现

扩展HystrixConcurrencyStrategy


/**
 * Hystrix线程池隔离支持日志链路跟踪
 *
 * @author yuhao.wang3
 */
public class MdcHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {

    @Override
    public <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();
        }

        @Override
        public T call() throws Exception {
            try {
                MDC.setContextMap(contextMap);
                return delegate.call();
            } finally {
                MDC.clear();
            }
        }
    }
}

通过装饰Callable类,我们在MdcAwareCallable#call()方法中先将MDC上下文复制到子线程。

注册插件

@Configuration
public class HystrixConfig {

    //用来拦截处理HystrixCommand注解
    @Bean
    public HystrixCommandAspect hystrixAspect() {
        return new HystrixCommandAspect();
    }

    @PostConstruct
    public 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值