dubbo3+sleuth+brave实现链路追踪及traceId未传递或不对应的原因分析

本文讲述了作者在从SpringCloudAlibaba+dubbo2+nacos1.4升级到dubbo3+nacos2的过程中遇到的链路追踪问题,以及通过修改brave.dubbo.TracingFilter解决服务消费者和服务提供者间traceId和spanId传递的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题场景

笔者之前一直使用SpringCloud Alibaba + dubbo2 + nacos1.4进行开发,但是目前naocs2、dubbo3也已经推出有一段时间并逐渐达到生产环境可用状态,所以笔者也希望用最新版本的nacos2及dubbo3尝尝鲜。但在搭建框架的过程中遇到了链路追踪的问题,所以在这里详细记录一下。

SpringCloud Alibaba + dubbo2 + nacos1

笔者基于dubbo2和nacos1的框架的依赖版本如下(这里只展示链路追踪相关依赖):

SpringCloud Alibaba 2.2.5.RELEASE
Springboot 2.3.7.RELEASE
Dubbo 2.7.8 
Nacos 1.4.3
spring-cloud-starter-sleuth 3.0.0
brave-instrumentation-dubbo 5.13.7

基于dubbo2和nacos1,该依赖版本网上都有较为成熟的搭建方案。直接引入依赖,按照度娘上的配置一下yml文件,就能实现链路追踪,配置过程不太困难。这里就不详细介绍了。

SpringCloud Alibaba + dubbo3 + nacos2

在搭建基于dubbo3和nacos2的框架时也希望能实现链路追踪。其中方案一和方案二是目前Dubbo3官方手册列举的实现方案。
方案一:Skywalking
听说是最简单的,但因为要额外部署Skywalking,所以我暂未尝试这种方案。
方案二:OpenTelemetry或brave
我根据dubbo3的文档进行依赖的引入和yml文件的配置,但是发现服务提供者日志正常写入了traceId和spanId,但服务消费者无论traceId还是spanId都没写入,这个在dubbo的GitHub issue中也未有人提问,所以最终也没找到解决方案。
方案三:sleuth+brave
我尝试了沿用SpringCloud Alibaba + dubbo2 + nacos1框架时的sleuth+brave方案实现链路追踪,但我引入sleuth+brave并根据SpringCloud Alibaba + dubbo2 + nacos1框架时的yml文件配置后,发现虽然服务消费者和服务提供者的日志都写入了traceId和spanId但两个服务的traceId不一致,变成各写各的了,整个追踪链条并未正确串联起来。 最终通过查找GitHub上的issue终于找到一个brave的dubbo2扩展能兼容dubbo3的解决方案,在这里感谢@ShenFeng312这位大佬。
GitHub issue的comment链接如下:
https://github.com/apache/dubbo/issues/11650#issuecomment-1446313706

解决方案

笔者用的依赖版本如下:

SpringCloud Alibaba 2021.0.5.0
Springboot 2.7.8
Dubbo 3.2.4 
Nacos 2.2.0
spring-cloud-starter-sleuth 3.1.9
brave-instrumentation-dubbo 5.16.0

解决方案非常简单,只需修改一行源码即可。
修改brave.dubbo.TracingFilter#invoke中的RpcContext.getContext().getAttachments()改为invocation.getAttachments()
修改前:
在这里插入图片描述
修改后:
在这里插入图片描述
PS: 因为是要修改依赖的源码,所以各位读者可以复制该类、修改这行、增加Dubbo的SPI来指向自定义的TracingFilter。又或者自行重新打包jar。这里就不详细叙述了。

原因

根据GitHub上https://github.com/apache/dubbo/issues/11650#issuecomment-1446313706中@ShenFeng312大佬的分析,主要是因为dubbo2和dubbo3的RpcContext中invcation的attachment属性的实现方式改变了导致的。从issue的回复中其实也看到@ShenFeng312大佬也向brave提交了merge request,让brave-instrumentation-dubbo能兼容dubbo3,但是brave的开发人员一直未同意合并,这里就不展开说了,大家有兴趣可以自行去GitHub上看看。

疑问

根据知其然,也要知其所以然的想法,我尝试分析其中的原因,但也产生了一些疑问,以下疑问也会在后续的排查过程中逐一解答。

疑问一:dubbo2中为什么直接用RpcContext.getContext().getAttachments()就能传递traceId而不用invocation.getAttachments()呢?
疑问二:为什么dubbo3中brave.dubbo.TracingFilter继续用RpcContext.getContext().getAttachments()是不行的呢?
疑问三:dubbo3中的RpcContext.getContext().getAttachments()和invocation.getAttachments()有什么区别?

排查过程

追踪brave.dubbo.TracingFilter#invoke方法的try…catch…部分可以看到,最终传递到下一个服务的参数是通过invocation的,而traceId和spanId是保存在invocation的attachment这个map中的。所以我们接下来排查的目标都是检查并验证最终invoke时invocation的attachment中有没有traceId和spanId为准。
在这里插入图片描述

排查疑问一:

在这里插入图片描述
根据上述思路及brave.dubbo.TracingFilter#invoke方法中的注释得知,其实clientHandler.handleSendWithParent(clientRequest, invocationContext)一直都只是在操作RpcContext.getContext()的attachment并未操作invocation中的attachment
在这里插入图片描述
而invocation中的attachment其实是直到invoker.invoke(invocation)时才在org.apache.dubbo.rpc.protocol.AbstractInvoker#invoke方法把RpcContext.getContext()的attachment注入到invocation中的attachment中
在这里插入图片描述
所以通过上面的代码跟踪可以发现,dubbo2中虽然一直都是在操作RpcContext.getContext()的attachment,但会在AbstractInvoker#invoke方法中invoke下一个服务的前一刻把RpcCotext.getContext()的attachment注入到invocation中的attachment中,最终还是通过invocation中的attachment传递traceId给下一个服务的。
综上所述,在dubbo2中通过RpcContext.getContext().getAttachments()来操作RpcContext的attachment最终都会在AbstractInvoker#invoke方法里被注入到invocation中的attachment中,所以dubbo2中是可以通过RpcContext.getContext().getAttachments()来传递traceId的

排查疑问二、三:

追踪dubbo3中的RpcContext.getContext().getAttachments():
在这里插入图片描述
比对dubbo2中的RpcContext.getContext().getAttachments():
在这里插入图片描述
通过比较dubbo3和dubbo2的RpcContext.getContext().getAttachments()的实现,可以发现,dubbo3实现方式完全不同了,这个改动在dubbo3的官方手册中其实是有提及的
在这里插入图片描述
正是因为RpcContext.getContext().getAttachments()的实现改动,dubbo3中RpcContext.getContext().getAttachments()返回的不是RpcContext中的attachment也不是invocation中的attachment。而是把RpcContext中的SERVER_ATTACHMENT、CLIENT_ATTACHMENT复制一份并返回。后面再怎么put参数进RpcContext中的attachment都没有用了,即使后面在AbstractInvoker#invoke方法中把RpcContext中的attachment注入进invocation的attachment也没用了,因为put参数的时候是put进RpcContext的attachment的副本,而不是RpcContext中的attachment本身
而且! 本身dubbo3中AbstractInvoker#invoke方法中把RpcContext中的attachment注入invocation的attachment的实现也变了
在这里插入图片描述
不过这里已经不重要了,因为put参数的时候是put进RpcContext中的attachment的副本并未put进RpcContext的任何属性中。
综上所述,通过上述对源码的分析也解释了疑问二疑问三,解释了dubbo3中的RpcContext.getContext().getAttachments()和invocation.getAttachments()有什么区别和为什么dubbo3中brave.dubbo.TracingFilter继续用RpcContext.getContext().getAttachments()是不行的。

总结分析

总的来说,主要是dubbo3的RpcContext被拆分为四大模块才导致brave的dubbo扩展不能直接用,但是其实改动起来还是比较简单的。上述如果有说的不对的地方,还请各位大佬指正。下面笔者还画了一张图来帮助理解:
在这里插入图片描述
最后,版权归作者所有,任何形式转载请联系作者,谢谢!

<think>嗯,用户问的是原来Spring Kafka使用SleuthBrave实现进行追踪,现在Spring Boot 3是怎么实现的。我需要回忆之前关于Spring Cloud SleuthSpring Boot 3的变化。 首先,之前用户提到过Spring Boot 3Sleuth的自动配置拆分到同的模块,比如Brave、OpenTelemetry等。原来的Sleuth在消息传递部分可能用了Brave的instrumentation模块,比如spring-cloud-sleuth-brave里的messaging支持。 现在Spring Boot 3应该迁移到了Micrometer Tracing,而Micrometer Tracing支持Brave和OpenTelemetry两种实现。所以对于Spring Kafka的追踪,可能现在是通过Micrometer Tracing Bridge来集成,比如使用micrometer-tracing-bridge-brave者micrometer-tracing-bridge-otel。 用户可能想知道具体的包路径者依赖变化。之前的实现是org.springframework.cloud.sleuth.brave.instrument.messaging,现在可能变成了io.micrometer.tracing.brave.bridge.BraveTracing者类似的路径。同时,需要确认是否还需要额外的依赖,比如Spring Boot 3中的actuator者micrometer-tracing依赖。 另外,用户可能关心配置上的变化,比如是否还需要Sleuth的配置,者是否迁移到了management.tracing下的配置。例如,之前的spring.sleuth.sampler现在可能变成了management.tracing.sampling.probability。 还要注意,新的实现可能通过自动配置来应用,需要正确的starter依赖,比如引入micrometer-tracing-bridge-bravebrave-instrumentation-messaging,以及对应的Kafka支持模块。 可能用户在实际迁移中遇到了问题,需要知道如何调整依赖和配置,所以需要详细说明新的实现方式和必要的步骤,避免混淆。同时,是否需要选择Brave还是OpenTelemetry,以及对应的依赖组合,这也是关键点。</think>以下是 Spring Boot 3实现 Kafka 链路追踪的 **新机制解析**,以及与旧版 Sleuth Brave 实现的对比: --- ### 旧版实现Spring Cloud Sleuth + Brave) **包路径**: `org.springframework.cloud.sleuth.brave.instrument.messaging.TracingChannelInterceptor` **原理**: 通过向 Kafka 的 `Producer` 和 `Consumer` 注入 Brave 的拦截器,在消息头中添加 `traceId` 和 `spanId`,实现跨服务链路上下文传递。 --- ### Spring Boot 3 新版实现(Micrometer Tracing + Brave/OpenTelemetry) **核心变化**: - **依赖迁移**:从 Spring Cloud Sleuth 迁移到 **Micrometer Tracing**(Spring Boot 原生支持的观测体系) - **模块解耦**:追踪实现Brave/OpenTelemetry)与消息中间件(如 Kafka)的集成逻辑分离 #### 具体实现路径 1. **Brave 方案** - **包路径**: `io.micrometer.tracing.brave.bridge.BraveTracing` `io.micrometer.tracing.brave.instrument.messaging.BraveKafkaTracing` - **依赖项**: ```xml <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-tracing-bridge-brave</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-tracing-instrument-kafka</artifactId> </dependency> ``` - **自动配置**: Spring Boot 3 通过 `KafkaAutoConfiguration` 自动注入 `TracingProducerInterceptor` 和 `TracingConsumerInterceptor`,无需手动配置。 2. **OpenTelemetry 方案** - **包路径**: `io.micrometer.tracing.otel.bridge.OtelTracing` `io.opentelemetry.instrumentation.kafkaclients.v2_6.TracingConsumerInterceptor` - **依赖项**: ```xml <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-tracing-bridge-otel</artifactId> </dependency> <dependency> <groupId>io.opentelemetry.instrumentation</groupId> <artifactId>opentelemetry-kafka-clients-2.6</artifactId> </dependency> ``` --- ### 配置示例 #### 1. 启用 Kafka 链路追踪(以 Brave 为例) ```yaml management: tracing: enabled: true sampling.probability: 1.0 # 100%采样 ``` #### 2. 消息头传播规则 旧版 Sleuth 的 `spring.sleuth.propagation.type` 已废弃,改用 OpenTelemetry 标准的 `W3C` 传播协议: ```yaml management: tracing: propagation.type: W3C # 默认值,兼容 OpenTelemetry 和 Brave ``` --- ### 关键差异对比 | **特性** | **旧版 (Sleuth + Brave)** | **新版 (Micrometer Tracing)** | |--------------------|---------------------------------------|-----------------------------------------------| | 依赖管理 | 强耦合 Spring Cloud Sleuth | 由 Spring Boot 原生支持,依赖 Micrometer Tracing | | 扩展性 | 仅支持 Brave | 支持 Brave 和 OpenTelemetry 双引擎 | | 配置属性 | `spring.sleuth.*` | `management.tracing.*` | | 协议标准 | Brave 私有 Headers | 默认 W3C TraceContext,兼容云原生生态 | | Kafka 拦截器注入方式 | 通过 `TracingChannelInterceptor` | 自动注入 `TracingProducerInterceptor`/`TracingConsumerInterceptor` | --- ### 开发者注意事项 1. **兼容性检查**: 确保 Kafka 客户端版本与 OpenTelemetry/Brave 的 instrumentation 库版本兼容(例如 `opentelemetry-kafka-clients-2.6` 对应 Kafka 2.6.x)。 2. **手动拦截器覆盖**: 若需自定义拦截逻辑,需禁用自动配置: ```java @SpringBootApplication(exclude = KafkaAutoConfiguration.class) ``` 3. **观测数据导出**: 链路数据需额外配置导出到 Zipkin/Jaeger/Wavefront,例如 Zipkin: ```xml <dependency> <groupId>io.zipkin.reporter2</groupId> <artifactId>zipkin-reporter-brave</artifactId> </dependency> ``` --- ### 总结 Spring Boot 3 通过 **Micrometer Tracing** 统一了链路追踪实现,Kafka 的集成从 `spring-cloud-sleuth` 迁移到标准化模块: - 使用 `micrometer-tracing-instrument-kafka` 实现消息拦截 - 通过 `management.tracing.*` 配置采样率和传播协议 - 开发者需根据选择的追踪引擎(Brave/OpenTelemetry)组合对应依赖
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值