《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-service
  zipkin:
    base-url: http://localhost:9411
    sender:
      type: web
  sleuth:
    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 {

    @Autowired
    private Tracer tracer;

    @Override
    public 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

📌 参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值