Spring Cloud Sleuth整合RxJava2单请求生成多Trace问题求助
我来帮你解决这个RxJava并行调用导致多Trace的问题!在Spring Cloud Edgware.RELEASE版本里,Sleuth对RxJava的线程上下文传递支持确实有缺陷——当你用RxJava做并行调用时,每个新启动的线程都会丢失原来的Trace上下文,进而生成全新的Trace ID,这就是你看到单次请求出12条Trace的原因。下面是具体的修复方案:
问题本质
Edgware版本的Sleuth没有自动对RxJava的Scheduler做Trace上下文传播处理,并行操作时每个Observable的订阅线程都会重新生成Trace,导致同一个请求被拆成了多个独立的Trace链。
解决步骤
1. 自定义RxJava Hook传递Trace上下文
你需要注册一个RxJava的执行Hook,把当前请求的Trace Span上下文手动传递到RxJava的每个线程中。创建一个配置类:
import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.Tracer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import rx.Observable; import rx.Subscriber; import rx.plugins.RxJavaObservableExecutionHook; @Configuration public class SleuthRxJavaContextConfig { private final Tracer tracer; // 通过构造注入Tracer实例 public SleuthRxJavaContextConfig(Tracer tracer) { this.tracer = tracer; } @Bean public RxJavaObservableExecutionHook sleuthRxJavaHook() { return new RxJavaObservableExecutionHook() { @Override public <T> Observable.OnSubscribe<T> onSubscribeStart(Observable<? extends T> observable, Observable.OnSubscribe<T> onSubscribe) { // 捕获当前请求的Trace Span Span currentSpan = tracer.getCurrentSpan(); // 包装订阅逻辑,在新线程中恢复Span上下文 return subscriber -> { try (Tracer.SpanInScope scope = tracer.withSpan(currentSpan)) { onSubscribe.call(subscriber); } }; } }; } }
2. 确保并行操作走Hook拦截逻辑
不管你用的是Observable.parallel()还是显式指定subscribeOn(Schedulers.io()),上面的Hook都会自动拦截Observable的订阅过程,把Trace上下文传递到新线程里。不需要额外修改你的业务代码,只需要让这个配置类被Spring扫描到即可。
3. 验证效果
重启服务后发起请求,去Zipkin后台查看Trace列表——现在单次请求应该只会生成1条Trace,所有RxJava并行调用的Span都会作为子Span挂在这条主Trace下面。
额外提示
- Edgware是比较老的Spring Cloud版本了,后续的Finchley及更高版本对RxJava的上下文传递做了原生支持,升级版本的话这个问题会自动消失。
- 如果你用的是RxJava 2.x,上面的代码需要调整为RxJava 2对应的Hook(比如
RxJavaPlugins.setObservableAssemblyHook()),不过Edgware版本默认适配的是RxJava 1.x,所以上面的代码应该刚好匹配你的场景。
内容的提问来源于stack exchange,提问作者Ankit Bansal
相关产品推荐
相关产品推荐

