当前位置: 首页 > ds >正文

《Spring 中上下文传递的那些事儿》Part 4:分布式链路追踪 —— Sleuth + Zipkin 实践

📝 Part 4:分布式链路追踪 —— Sleuth + Zipkin 实践

在微服务架构中,一个请求可能会经过多个服务节点。为了准确地监控调用链、定位性能瓶颈和排查问题,分布式链路追踪(Distributed Tracing) 是必不可少的能力。

Spring Cloud 提供了对 Sleuth + Zipkin 的开箱即用支持,帮助开发者轻松实现全链路追踪。本文将带你了解 Sleuth 和 Zipkin 的工作原理,并结合实际项目演示如何配置和使用它们。


一、什么是 Sleuth?

Spring Cloud Sleuth 是 Spring Cloud 提供的一个分布式请求链路追踪组件。它可以在不修改业务逻辑的前提下,自动为每个请求生成唯一的 traceIdspanId,并注入到日志、消息、RPC 调用等上下文中。

核心概念:

概念说明
traceId唯一标识一次完整的请求链路,贯穿整个调用树
spanId表示调用链中的一个节点(即一次服务调用或操作)
exportable是否将 span 数据发送给 Zipkin 等收集系统

二、什么是 Zipkin?

Zipkin 是 Twitter 开源的一款分布式追踪系统,用于收集 Sleuth 产生的 trace 数据,并提供可视化界面展示调用链、耗时分析、服务依赖等信息。

你可以将其理解为 Sleuth 的“数据接收器 + 可视化平台”。


三、Sleuth 如何与 MDC、ThreadLocal 协作?

Sleuth 在底层通过 MDC 注入 traceIdspanId,从而让日志框架能够识别这些字段。这使得我们在日志中可以清晰地看到每次请求的调用路径。

示例日志输出:

2025-07-03 17:00:00.000 [http-nio-8080-exec-1] INFO  c.e.demo.service.UserService - Processing user request
[applicationName,9e6b50dc63abea4c,9e6b50dc63abea4c] true

其中:

  • applicationName 是服务名;
  • 9e6b50dc63abea4ctraceId
  • 第二个值是 spanId

四、快速接入 Sleuth + Zipkin

1. 添加依赖(Maven)

<!-- 引入 Sleuth -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency><!-- 引入 Zipkin 收集器 -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

2. 配置 application.yml

spring:application:name: user-servicezipkin:base-url: http://localhost:9411sender:type: websleuth:sampler:probability: 1.0  # 采样率,1.0 表示全部采集

✅ 注意:zipkin.base-url 应指向你部署的 Zipkin Server 地址。


五、启动 Zipkin Server

你可以通过 Docker 快速启动 Zipkin:

docker run -d -p 9411:9411 openzipkin/zipkin

访问 http://localhost:9411 即可打开 Zipkin UI。


六、多服务调用链演示

假设我们有三个服务:

  • gateway-service(网关)
  • user-service(用户服务)
  • order-service(订单服务)

gateway-service 调用 user-service,再由 user-service 调用 order-service 时,Sleuth 会自动生成如下结构:

Trace ID: abcdefghijklmnop
└── Span 1: gateway-service -> user-service└── Span 2: user-service -> order-service

Zipkin UI 会展示完整的调用链、各服务耗时、错误信息等。


七、异步任务中的上下文传递

Sleuth 内部已经集成对异步任务的支持,例如:

  • @Async
  • CompletableFuture
  • ScheduledExecutorService

只需引入正确的依赖(如 spring-context-support),Sleuth 就能自动传播 traceId 到子线程中。

如果你使用的是自定义线程池,推荐使用 TtlExecutors 包装线程池以确保上下文正确传递:

ExecutorService executor = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(2));

八、日志格式配置(logback.xml)

为了让日志中显示 traceIdspanId,你需要配置日志模板:

<configuration><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg [traceId=%X{traceId}, spanId=%X{spanId}]%n</pattern></encoder></appender><root level="info"><appender-ref ref="STDOUT"/></root>
</configuration>

这样每条日志都会带上当前的 traceIdspanId,便于排查问题。


九、Dubbo 微服务中 Sleuth 的兼容性

在 Dubbo 微服务中,Sleuth 默认只支持基于 HTTP 的调用,因此需要额外配置才能实现 Dubbo 协议下的上下文透传。

解决方案:

  1. 手动注入 RpcContext
String traceId = tracer.currentSpan().context().traceIdString();
RpcContext.getContext().setAttachment("X-B3-TraceId", traceId);
  1. 使用 Dubbo Filter 自动注入上下文
@Activate(group = {Constants.PROVIDER, Constants.CONSUMER})
public class TraceFilter implements Filter {@Autowiredprivate Tracer tracer;@Overridepublic Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {String traceId = tracer.currentSpan().context().traceIdString();RpcContext.getContext().setAttachment("X-B3-TraceId", traceId);return invoker.invoke(invocation);}
}
  1. 使用 Apache SkyWalking 替代方案(更高级)

如果 Dubbo 服务较多,建议直接使用 SkyWalkingJaeger 等 APM 工具进行全链路追踪。


十、总结建议

组件推荐配置
日志追踪使用 Sleuth 自动生成 traceId/spanId
日志格式结合 MDC 打印 traceId、spanId
多服务调用Sleuth + Zipkin 实现全链路追踪
异步任务使用 TTL 或 Sleuth 自带的线程池封装
Dubbo 微服务自定义 Filter 注入上下文,或使用 SkyWalking

📌 参考链接

  • Spring Cloud Sleuth 官方文档
  • Zipkin GitHub
  • Dubbo 全链路追踪
http://www.xdnf.cn/news/14976.html

相关文章:

  • Python 闭包(Closure)实战总结
  • 【PyCharm 2025.1.2配置debug】
  • 分类树查询性能优化:从 2 秒到 0.1 秒的技术蜕变之路
  • 低代码实战训练营教学大纲 (10天)
  • [特殊字符] 电子机械制动(EMB)产业全景分析:从技术演进到千亿市场爆发
  • 网络编程学习路线图
  • Python 爬虫实战 | 国家医保
  • OpenBayes 教程上新丨医疗VLM新突破!HealthGPT对复杂MRI模态理解准确率达99.7%,单一模型可处理多类生成任务
  • 一天两道力扣(1)
  • 高效打字辅助工具,解决符号输入难题
  • 使用pdf box去水印
  • Part 0:射影几何,变换与估计-第三章:3D射影几何与变换
  • 分享|大数据分析师职业技术证书报考指南
  • 推荐系统中如果有一个上古精排模型,后续如何优化?
  • 遇到该问题:kex_exchange_identification: read: Connection reset`的解决办法
  • github在线图床
  • PostgreSQL中的rank()窗口函数:实用指南与示例
  • 浏览器原生控件上传PDF导致hash值不同
  • 制作一款打飞机游戏76:分数显示
  • 微软广告推出新的精细资产级别审核
  • 无代码自动化测试工具介绍
  • SpringBoot控制反转
  • CentOS 6操作系统安装
  • 05.SpringBoot拦截器的使用详解
  • 玄机——某学校系统中挖矿病毒应急排查
  • 人脸活体识别3:C/C++实现人脸眨眼 张嘴 点头 摇头识别(可实时检测)
  • lerobot 工程笔记(一)——使用smolvla控制so101
  • 【AI落地应用实战】AIGC赋能职场PPT汇报:从效率工具到辅助优化
  • Docker Compose 基础——AI教你学Docker
  • 链表的实现