一句话总结
链路追踪用于追踪一次请求在微服务间的完整调用链,快速定位性能瓶颈和故障点。核心概念: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 + Zipkin | SkyWalking |
|---|---|---|
| 侵入性 | 需引入依赖 | Java Agent(无侵入) |
| 功能 | 链路追踪 | 链路追踪 + 性能监控 + 告警 |
| 存储 | MySQL/ES/内存 | ES/H2/MySQL |
| 性能损耗 | 较低 | 较低 |
| 多语言 | 仅 Java | Java/.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。