SpringCloud 核心组件解析:服务链路追踪
技术栈 :Spring Boot 3.2.0 + Spring Cloud 2023.0.0 + Micrometer Tracing + Zipkin
已不维护:Spring Cloud Sleuth → 替代用 Micrometer Tracing
5.1 是什么 --- 链路追踪的核心概念
5.1.1 生活化类比:快递追踪
你在淘宝买了 3 件商品,想知道它们到哪了:
快递单号 SF1234567890(Trace ID)
├── [扫描点 A] 北京分拣中心 12:00 → 12:05 (Span 1)
│ └── [扫描点 B] 北京→上海 运输 12:05 → 18:00 (Span 2)
│ └── [扫描点 C] 上海配送站 → 签收 18:30 (Span 3)
- Trace ID = 快递单号:贯穿整个流程的唯一标识
- Span = 扫描记录:每个环节的处理记录(时间、地点、操作)
- Parent Span → Child Span:表达了调用层级关系
5.1.2 技术定义
在微服务中,一个用户请求可能经过 N 个服务。链路追踪就是给每个请求分配一个全局唯一 ID,记录它经过的每个服务及耗时。
用户 → Order Service (Span A, parent=null)
│ HTTP 调用
├→ Payment Service (Span B, parent=Span A)
│ │ Feign 调用
│ └→ Account Service (Span C, parent=Span B)
│
└→ Inventory Service (Span D, parent=Span A)
Trace ID: 5f7a3b2c... 贯穿整棵树
Span ID: A/B/C/D... 每个节点一个 ID
5.2 为什么 --- 没有链路追踪的痛点
5.2.1 场景
线上用户反馈"下单等了 10 秒才成功",已知调用链:Nginx → Gateway → Order → Payment → Account。
❓ 到底哪个环节慢了?
❓ 是数据库慢还是网络慢?
❓ 10s 里各环节分别占多少?
❓ 有没有哪个服务报错了?
没有链路追踪,排查方式 = 挨个服务查日志 + 靠时间戳对着拼。20 个服务时这是灾难。
5.2.2 Sleuth 的贡献与谢幕
Spring Cloud Sleuth 早期做了两件最重要的事:
- 自动生成 TraceId/SpanId 并注入到日志 MDC
- 通过 HTTP Header 跨服务传播 (
X-B3-TraceId、X-B3-SpanId)
经典日志格式:
2024-10-20 10:00:01.123 INFO [order-service, abc123, def456, true] 创建订单成功
└─服务名 └─TraceId └─SpanId └─是否上报
⚠️ Spring Boot 3.x 中 Sleuth 被 Micrometer Tracing 取代,API 发生重大变化。
5.3 怎么做 --- Micrometer Tracing + Zipkin 完整集成
5.3.1 小 Demo:先暴露痛点
在 Provider 中故意加延时模拟慢查询:
java
@GetMapping(value = "/pay/get/{id}")
public ResultData<Pay> getById(@PathVariable("id") Integer id) {
// 模拟慢查询:故意 sleep 62 秒
try { TimeUnit.SECONDS.sleep(62); } catch (Exception e) { e.printStackTrace(); }
return ResultData.success(payService.getById(id));
}
Consumer 调用后:不知道 Provider 内部耗时多少,日志里只有一个总耗时。
5.3.2 6 个核心依赖详解
| 序号 | 依赖 | GAV | 作用 |
|---|---|---|---|
| 1 | micrometer-tracing-bom | io.micrometer |
BOM 版本管理,统一版本 |
| 2 | micrometer-tracing | io.micrometer |
核心 API,创建 Trace/Span |
| 3 | micrometer-tracing-bridge-brave | io.micrometer |
将 Micrometer API 桥接到 Brave(Zipkin 的 Java 实现) |
| 4 | micrometer-observation | io.micrometer |
Observation API,统一 metrics/tracing/logging |
| 5 | feign-micrometer | io.github.openfeign |
让 Feign 客户端自动生成 Span |
| 6 | zipkin-reporter-brave | io.zipkin.reporter2 |
将 Span 数据异步发送到 Zipkin Server |
xml
<!-- 父 POM 中统一管理版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bom</artifactId>
<version>1.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
5.3.3 Provider 端配置
yaml
# 注意:Spring Boot 3.x 中配置前缀改变了!
management:
zipkin:
tracing:
endpoint: http://localhost:9411/api/v2/spans # Zipkin Server 地址
tracing:
sampling:
probability: 1.0 # 采样率:开发=1.0(全部),生产=0.1(10%)
5.3.4 Consumer 端无需额外配置
Feign 自动传播 TraceId:feign-micrometer 会在每次 Feign 请求的 Header 中自动注入 traceparent(W3C 标准格式)。
5.3.5 启动 Zipkin Server
bash
# Docker 方式
docker run -d -p 9411:9411 openzipkin/zipkin
# 或下载 jar
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar
5.3.6 验证
访问 Consumer → Provider → 打开 http://localhost:9411 → 点击"Run Query":
Trace: 5f7a3b2c1d4e...
├── cloud-consumer-order-openfeign: 5ms
│ └── cloud-payment-service: 62s ← 一眼定位!
└── Total: 62s
5.4 深入原理
5.4.1 Trace 传播机制
Consumer Provider
│ │
│ GET /feign/micrometer/1 │
│ Header: traceparent: │
│ 00-abc123-def456-01 │
│ ──────────────────────────────→ │
│ │ 提取 TraceId=abc123
│ │ 创建新 Span,parentSpanId=def456
│ │
│ ← 200 OK │
│ │
├→ 上报 Span(consumer-side) → Zipkin
└→ 上报 Span(provider-side) → Zipkin
W3C Trace Context 标准 Header:
traceparent: 00-{trace-id}-{parent-span-id}-{trace-flags}
│ │ │ └─ 01=采样
│ │ └─ 父 Span ID
│ └─ 全局 Trace ID(32位hex)
└─ 版本号(当前为 00)
5.4.2 采样策略
| 策略 | 配置 | 效果 |
|---|---|---|
| Always 全部采样 | probability: 1.0 |
开发环境、排查问题 |
| Probability 按比例 | probability: 0.1 |
生产环境,10% 采样 |
| RateLimit 每秒N条 | 需自定义 Sampler | 按秒限制总条数 |
| Never 不采样 | probability: 0 |
关闭追踪 |
java
// 自定义采样器 Bean
@Bean
public SamplerFunction<HttpRequest> mySampler() {
return request -> {
// 健康检查接口不采样
if (request.path().startsWith("/actuator")) return false;
return true;
};
}
5.5 对比分析
| 维度 | Sleuth | Micrometer Tracing |
|---|---|---|
| Spring Boot 版本 | 2.x | 3.x |
| 底层 API | Brave/OpenTelemetry | Observation API 统一抽象 |
| 配置前缀 | spring.sleuth.* |
management.tracing.* |
| 日志 MDC | 自动注入 TraceId/SpanId | 需手动配置 logging.pattern.level |
| Feign 集成 | spring-cloud-sleuth |
feign-micrometer |
| 未来方向 | 停止维护 | Spring 主推 |
5.6 面试题
Q1:Sleuth 和 Micrometer Tracing 的核心区别?
答:
- Sleuth 仅用于 Spring Boot 2.x,Micrometer Tracing 用于 3.x。
- Micrometer Tracing 使用 Observation API 统一了 metrics/tracing/logging 三个维度。
- 配置前缀从
spring.sleuth.*变为management.tracing.*。 - Micrometer Tracing 是 Spring 官方的长远方向。
Q2:TraceId 是如何跨服务传播的?
答 :通过 HTTP Header 传播。Feign 自动在请求中添加 traceparent(W3C 标准)或 X-B3-TraceId 等 Header,下游服务从 Header 中提取 TraceId,创建子 Span。
Q3:高并发场景下如何平衡链路追踪的性能开销?
答:
- 降低采样率 :生产环境设为 0.010.1(1%10%)
- 使用异步上报:Zipkin Reporter 默认异步,不阻塞业务线程
- 配置 Span 数量上限:单个 Trace 最多创建 N 个 Span
- 使用消息队列缓冲:Zipkin → Kafka → Zipkin Server
5.7 踩坑指南
| 坑 | 现象 | 原因 | 解决 |
|---|---|---|---|
| 🔴 配置不生效 | Zipkin 收不到数据 | Spring Boot 3.x 配置前缀从 spring.zipkin 改为 management.zipkin |
检查配置路径 |
| 🔴 Feign 不传播 TraceId | Zipkin 中 Consumer 和 Provider 是两条独立的 Trace | 缺少 feign-micrometer 依赖 |
必须引入 6 个依赖中的第 5 个 |
| 🔴 采样率 1.0 导致 OOM | Zipkin 内存爆炸 | 生产环境全量采样产生海量 Span | 生产设为 0.1 |
| 🔴 Zipkin 端口冲突 | Zipkin 启动失败 | 9411 端口被占用 | 换端口或 kill 占用进程 |
5.8 章节总结
| 要点 | 说明 |
|---|---|
| 核心概念 | Trace(全局链路)+ Span(每个节点)+ Propagation(跨服务传递) |
| Sleuth→Micrometer | Spring Boot 3.x 中 Sleuth 被取代,API 和配置前缀都变了 |
| 6 个依赖 | tracing + brave-bridge + observation + feign-micrometer + zipkin-reporter + tracing-bom |
| 关键配置 | management.zipkin.tracing.endpoint + management.tracing.sampling.probability |
| Feign 自动传播 | feign-micrometer 自动在 Header 中注入 W3C 标准的 traceparent |
| 采样率 | 开发 1.0,生产 0.01~0.1 |