Hystrix implements ThreadLocal context transfer between main thread and sub-thread

Keywords: Programming github Spring

Problem description

When I use log link tracking( Link Tracking of Logs Based on SLF4J MDC Mechanism I found that when using Hystrix thread pool isolation, I couldn't copy the MDC context of the main thread from the sub-thread.( Slf4j MDC mechanism The log link is blocked.

problem analysis

Hystrix thread pool isolation is implemented using Hystrix ThreadPool. The Hystrix ThreadPool is obtained in the Hystrix Concurrent Strategy. Here we can see the description of the class:

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.

In general, Hystrix Concurrent Strategy provides a default concurrency strategy implementation. We can expand it by decoration according to our different needs. If the wrapCallable method is invoked every time HystrixCommand is executed, we can decorate the Callable to provide additional functionality (such as ThreadLocal context delivery). The plug-in documentation is also attached: https://github.com/Netflix/Hystrix/wiki/Plugins.

Opening the document will teach us how to extend Hystrix Concurrent Strategy and make it work.

Realization

Extending Hystrix Concurrent Strategy


/**
 * Hystrix Thread pool isolation supports log link tracking
 *
 * @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();
            }
        }
    }
}

By decorating the Callable class, we first copy the MDC context to the sub-threads in the MdcAware Callable# call () method.

Registration plug-in

@Configuration
public class HystrixConfig {

    //Used to intercept and process HystrixCommand annotations
    @Bean
    public HystrixCommandAspect hystrixAspect() {
        return new HystrixCommandAspect();
    }

    @PostConstruct
    public void init() {
        HystrixPlugins.getInstance().registerConcurrencyStrategy(new MdcHystrixConcurrencyStrategy());
    }

}

Reference resources: https://github.com/Netflix/Hystrix/wiki/Plugins#concurrencystrategy

Source code

https://github.com/wyh-spring-ecosystem-student/spring-boot-student/tree/releases

spring-boot-student-hystrix project

Laying-cache, a multi-level caching framework for monitoring This is an implementation of my open source multi-level caching framework. If you are interested, take a look at it.

Posted by andyhajime on Mon, 30 Sep 2019 23:50:50 -0700