Hystrix实现主线程和子线程的ThreadLocal上下文传递

问题描述

我在使用日志链路追踪的时候(基于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 https://github.com/Netflix/Hystrix/issues/351 for a more detailed discussion.
See HystrixPlugins or the Hystrix GitHub Wiki for information on configuring plugins: https://github.com/Netflix/Hystrix/wiki/Plugins.

大致意思是HystrixConcurrencyStrategy提供了一套默认的并发策略实现。我们可以根据我们自己不同需求通过装饰去扩展它。如每次执行HystrixCommand的时候都会去调用wrapCallable(Callable) 方法,这里我们就可以通过装饰Callable使它提供一些额外的功能(如ThreadLocal上下文传递)。还附上了插件的文档:https://github.com/Netflix/Hystrix/wiki/Plugins。

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


如何去扩展.png

是扩展生效.png

实现

扩展HystrixConcurrencyStrategy


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

    @Override
    public  Callable wrapCallable(Callable callable) {
        return new MdcAwareCallable(callable, MDC.getCopyOfContextMap());
    }

    private class MdcAwareCallable implements Callable {

        private final Callable delegate;

        private final Map contextMap;

        public MdcAwareCallable(Callable callable, Map 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

spring-boot-student-hystrix 工程

为监控而生的多级缓存框架 layering-cache这是我开源的一个多级缓存框架的实现,如果有兴趣可以看一下

你可能感兴趣的:(Hystrix实现主线程和子线程的ThreadLocal上下文传递)