问题描述

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

问题分析

Hystrix的线程池隔离是使用HystrixThreadPool来实现的。而获取HystrixThreadPool是在HystrixConcurrencyStrategy。在这里我们可以看到类的描述:

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

打开文档,将会教我们如何去扩展HystrixConcurrencyStrategy并使它生效。Hystrix实现主线程和子线程的ThreadLocal上下文传递-LMLPHPHystrix实现主线程和子线程的ThreadLocal上下文传递-LMLPHP

实现

扩展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

spring-boot-student-hystrix 工程

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

09-23 17:02