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... 每个节点一个 ID5.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 中故意加延时模拟慢查询:
@GetMapping(value="/pay/get/{id}")publicResultData<Pay>getById(@PathVariable("id")Integerid){// 模拟慢查询:故意 sleep 62 秒try{TimeUnit.SECONDS.sleep(62);}catch(Exceptione){e.printStackTrace();}returnResultData.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 |
<!-- 父 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 端配置
# 注意: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
# Docker 方式dockerrun-d-p9411:9411 openzipkin/zipkin# 或下载 jarcurl-sSLhttps://zipkin.io/quickstart.sh|bash-sjava-jarzipkin.jar5.3.6 验证
访问 Consumer → Provider → 打开http://localhost:9411→ 点击"Run Query":
Trace: 5f7a3b2c1d4e... ├── cloud-consumer-order-openfeign: 5ms │ └── cloud-payment-service: 62s ← 一眼定位! └── Total: 62s5.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) → ZipkinW3C 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 | 关闭追踪 |
// 自定义采样器 Bean@BeanpublicSamplerFunction<HttpRequest>mySampler(){returnrequest->{// 健康检查接口不采样if(request.path().startsWith("/actuator"))returnfalse;returntrue;};}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 |