Sleuth的原理是在Thread里面保存了当前的Trace/Span等信息,通过MDC传给了selfj用来打日志。在调用到Feign、MQ的时候,通过把Thread里面的信息,保存到远程调用的Header里面,传给下一个服务。这在你是一个线程里面执行的时候没有问题。比如你A调用B服务,A是通过Http同步调用,那么没问题。如果A调用B是异步调用,问题就来了:在异步调用的线程里面,并没有之前线程的信息,那么TraceId、Span等信息自然会被清空,这样下一步调用就无法继承到TraceId,也就无法跟踪了。
看了Sleuth给的解决方案,是一个叫LazyTraceExecutor的东西,传入BeanFactory和Executor,就可以用他异步执行一个Runnable。还有一个LazyTraceThreadPoolTaskExecutor,是用了ThreadPoolTaskExecutor来执行的。他的原理是注入了Tracer,TraceKeys,SpanNamer三个Bean,最后利用SpanContinuingTraceRunnable来执行。我们自己可以这么写:
@Autowired Tracer tracer; @Autowired TraceKeys traceKeys; @Autowired SpanNamer spanNamer; scheduledExecutorService.schedule(new SpanContinuingTraceCallable<Void>(tracer,traceKeys,spanNamer,()->{ //这里写自己的代码 return null; }), delay);
这样就可以把Trace信息传递过去了。