链路追踪 Sleuth + Zipkin?

2025年 阅读约 15 分钟 面试指南 · Spring Cloud

深入解析链路追踪:Sleuth + Zipkin、TraceId/SpanId概念、日志聚合与调用链分析、Feign传递TraceId、与SkyWalking对比,附面试模拟问答。

一句话总结

链路追踪用于追踪一次请求在微服务间的完整调用链,快速定位性能瓶颈和故障点。核心概念:TraceId(全局唯一,标识一次完整请求)、SpanId(标识一次调用,有父子关系)。Sleuth 负责生成和传递 TraceId/SpanId,Zipkin 负责收集、存储和展示调用链数据。Sleuth 3.x 已迁移到 Micrometer Tracing,生产环境推荐 SkyWalking(功能更全、无代码侵入)。

初级理解

为什么需要链路追踪?

# 微服务调用链问题 # 用户请求 → Gateway → 订单服务 → 用户服务 → 数据库 # ↓ # 库存服务 → 缓存 # ↓ # 支付服务 → 第三方支付 # 问题 # 1. 请求慢了,不知道慢在哪个服务 # 2. 报错了,不知道是哪个环节出错 # 3. 调用链太长,难以排查 # 链路追踪解决 # 1. 完整调用链可视化 # 2. 每个环节的耗时一目了然 # 3. 快速定位性能瓶颈和故障点

核心概念

# TraceId:全局追踪 ID # 一次完整请求的唯一标识 # 从请求进入第一个服务开始生成 # 在整个调用链中传递,保持不变 # SpanId:跨度 ID # 一次调用的唯一标识 # 有父子关系:A 调用 B,A 的 SpanId 是 B 的 ParentSpanId # 示例 # TraceId: abc123 # ├── Span1: Gateway 接收请求 (SpanId=1, ParentSpanId=null) # │ └── Span2: 调用订单服务 (SpanId=2, ParentSpanId=1) # │ └── Span3: 调用用户服务 (SpanId=3, ParentSpanId=2) # │ └── Span4: 调用库存服务 (SpanId=4, ParentSpanId=2)

中级深入

Sleuth + Zipkin 使用

# 1. 引入依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> </dependency> # 2. 配置 spring: sleuth: sampler: probability: 1.0 # 采样率(1.0 = 100%) zipkin: base-url: http://localhost:9411 # Zipkin 地址 # 3. 日志自动添加 TraceId # 2025-01-01 10:00:00.123 [user-service,abc123,def456] INFO ... # 服务名 TraceId SpanId # 4. Zipkin 界面查看调用链 # http://localhost:9411 # 按服务名、时间范围查询调用链 # 查看每个 Span 的耗时、状态

TraceId 传递

# Feign 自动传递 TraceId # Sleuth 自动在 Feign 请求头中添加 # X-B3-TraceId: abc123 # X-B3-SpanId: def456 # X-B3-ParentSpanId: ghi789 # 线程池中传递 TraceId # 问题:异步线程会丢失 TraceId # 解决:使用 Sleuth 的 LazyTraceExecutor @Bean public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); // Sleuth 自动包装,传递 TraceId return new LazyTraceExecutor(beanFactory, executor); }

高级拓展

Sleuth vs SkyWalking

对比维度Sleuth + ZipkinSkyWalking
侵入性需引入依赖Java Agent(无侵入)
功能链路追踪链路追踪 + 性能监控 + 告警
存储MySQL/ES/内存ES/H2/MySQL
性能损耗较低较低
多语言仅 JavaJava/.NET/Node.js 等

Micrometer Tracing(Sleuth 3.x)

# Sleuth 3.x 已迁移到 Micrometer Tracing # 新依赖 <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-tracing-bridge-brave</artifactId> </dependency> # 新配置 management: tracing: sampling: probability: 1.0 zipkin: tracing: endpoint: http://localhost:9411/api/v2/spans # 变化 # 1. 包名从 spring.cloud.sleuth → io.micrometer.tracing # 2. API 统一(不绑定 Sleuth) # 3. 支持多种追踪后端(Zipkin、Jaeger、OpenTelemetry)

实战场景

场景:通过 TraceId 排查慢请求

# 排查步骤 # 1. 用户反馈某个请求慢 # 2. 从日志中找到该请求的 TraceId # grep "用户ID" app.log | grep "TraceId" # 3. 在 Zipkin 中搜索 TraceId # 4. 查看调用链,找到耗时最长的 Span # 5. 定位到具体服务和接口 # 6. 分析该接口的慢原因(SQL、网络、代码) # 日志示例 # [user-service,abc123,span1] 调用用户服务 耗时 50ms # [order-service,abc123,span2] 调用订单服务 耗时 2000ms ← 瓶颈 # [product-service,abc123,span3] 调用商品服务 耗时 30ms

面试模拟

面试官:TraceId 和 SpanId 是什么关系?

你:TraceId 是一次完整请求的全局唯一标识,在整个调用链中不变。SpanId 是一次调用的标识,有父子关系。一个 Trace 包含多个 Span,形成树形结构。

面试官:Sleuth 和 SkyWalking 怎么选?

你:SkyWalking 功能更全(链路追踪+性能监控+告警),Java Agent 无代码侵入,支持多语言。Sleuth 需要引入依赖,功能较单一。生产环境推荐 SkyWalking。