Java线程信息传递_Sleuth 信息在线程之间的传递

本文纠正了Sleuth在多线程环境下自动传递traceId的误解,并通过分析LazyTraceExecutor的源码揭示了其工作原理。探讨了如何利用InheritableThreadLocal在用户自定义线程间传递信息,提出了弥补Sleuth短板的解决方案,建议读者通过Filter和TraceFeignClient实现Trace信息复用。
摘要由CSDN通过智能技术生成

1. 问题

上期说,Sleuth作为微服务下的调用链框架,支持traceId在各种多线程情况下的传递。很抱歉,这个结论是错的,我在这里向大家道歉

2. 分析

得出这个结论是因为官方文档的一句话链接:

We’re providing LazyTraceExecutor, TraceableExecutorService and TraceableScheduledExecutorService. Those implementations are creating Spans each time a new task is submitted, invoked or scheduled.

翻译:我们提供LazyTraceExecutor, TraceableExecutorService和TraceableScheduledExecutorService这三个实现类,以期在一个新线程任务提交、执行或调度时创建新的Span

这句话很有迷惑性,很容易让人误解(好吧我承认,目前只有我),认为Sleuth支持各种多线程。遗憾的是,如果你手动创建了一个Thread,调用下一级服务时,Sleuth并不能感知到

3. 证明

3.1 方法一

写个Demo看下,是否TraceId能够正常传过去

3.2 方法二

我们看下LazyTraceExecutor是怎么做的

public class LazyTraceExecutor implements java.util.concurrent.Executor {

private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());

private Tracer tracer;

private final BeanFactory beanFactory;

private final Executor delegate;

private TraceKeys traceKeys;

private SpanNamer spanNamer;

public LazyTraceExecutor(BeanFactory beanFactory, Executor delegate) {

this.beanFactory = beanFactory;

this.delegate = delegate;

}

@Override

public void execute(Runnable command) {

if (this.tracer == null) {

try {

this.tracer = this.beanFactory.getBean(Tracer.class);

}

catch (NoSuchBeanDefinitionException e) {

this.delegate.execute(command);

return;

}

}

this.delegate.execute(new SpanContinuingTraceRunnable(this.tracer, traceKeys(), spanNamer(), command));

}

}

使用方式

@Configuration

public class MyConfiguration {

@Autowired

BeanFactory beanFactory;

@Bean

public Executor executor() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

// CUSTOMIZE HERE

executor.setCorePoolSize(7);

executor.setMaxPoolSize(42);

executor.setQueueCapacity(11);

executor.setThreadNamePrefix("MyExecutor-");

// DON'T FORGET TO INITIALIZE

executor.initialize();

return new LazyTraceExecutor(this.beanFactory, executor);

}

}

所以它能在线程之间传递traceId并不稀奇,因为它根本就是要你使用它的多线程工具。

4.能否让子线程获取父线程信息呢

4.1 能:InheritableThreadLocal

一般来说,每个线程一个副本,我们都是用ThreaLocal。可是,如果你想要该线程和它的子线程都能读这个副本,那就可以用InheritableThreadLocal了。

用法很简单Demo:

private static final ThreadLocal sessionInfoHolder1 = new ThreadLocal();

private static final ThreadLocal sessionInfoHolder2 = new InheritableThreadLocal();

5. 思考

既然Sleuth不支持用户自己创建线程,而使用InheritableThreadLocal可以解决这个问题,那么是不是说,Sleuth这个短板其实是可以解决的?

5.1 方案

Filter中获取TraceId,存入:InheritableThreadLocal

TraceFeignClient中判断当前线程或其父线程中是否有traceId,如果有,就证明是用户new的线程,即可复用Trace信息。

有兴趣的读者可以去Sleuth拉个分支试下,说不定会被管理员merge

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值