适用读者:微服务排障时靠"挨台机器看日志"的人。
前置:S16-B03(集成测试)、S02(HTTP 基础)、S17(微服务雏形)。
覆盖旧文:A-560 → 143 点(§1 为什么需要链路追踪、§2 Trace 与 Span、Parent Span、Zipkin/Sleuth 定位)。
扩展点:E-S16-005(Trace 与 Span 的边界)。
上一篇:S16-B04 · 端到端:跑通完整流程才算真正验证
下一篇:S16-J02 · Spring Boot 3 接入实战。
1. 一句话结论
链路追踪解决的是"同一次请求在 N 个进程里的身份问题"。 它不告诉你"哪里慢",但它告诉你"这 8 秒的 8 个片段分别属于谁"——慢的定位是从这里开始的。
| 单体时代 | 微服务时代 |
|---|---|
| 一个日志文件里搜一次请求 | 5 台机器、5 个日志文件,靠 traceId 串起来 |
| 看堆栈就知道调用链 | 调用链本身要被记录才存在 |
2. 三个概念,一句话各自定义(A-560)
| 概念 | 定义 | 类比 |
|---|---|---|
| Trace | 一次完整请求的生命周期,由一个 traceId 标识 |
快递单号 |
| Span | 请求中的一个操作片段(一次 RPC、一次 SQL、一次缓存访问) | 中转站扫描记录 |
| Parent Span | 当前 span 的上游调用者;决定 span 树的形状 | 上一站 |
TraceId = af27c910...
Gateway (spanId=001, parent=null)
└── Order (spanId=002, parent=001)
├── MySQL (spanId=003, parent=002)
├── Redis (spanId=004, parent=002)
└── Payment (spanId=005, parent=002)
└── HTTP (spanId=006, parent=005) → 第三方支付
判据:拿到一个 traceId,能不能在 UI 里还原出这棵树?能 → 埋点正确;只能看到零散记录 → 上下文没传播(J02)。
3. Trace 与 Span 的边界(E-S16-005)
新手最容易犯的错是"什么都建 span",导致树爆炸、开销上升。判据三条:
| 该新建 span | 不该新建 |
|---|---|
| 跨进程调用(HTTP/RPC/MQ) | 同类内部的小函数调用 |
| I/O 边界(SQL、Redis、文件、外部 API) | 纯计算(用 profiling 看,不用 span) |
| 有明显耗时或失败可能的阶段 | 循环里的每次迭代(用 span 的 attribute 记次数) |
经验值:一次请求 10–50 个 span 属正常;上千个说明建错了层级。
4. 上下文传播:traceparent 到底传了什么
W3C Trace Context 规定的标准头(跨语言、跨厂商的事实标准):
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
┬─ ───────────────┬─────────────── ────────┬────── ─┬
│ │ │ └ flags(01=采样)
│ │ └ parent-id(16 hex)
│ └ trace-id(32 hex)
└ version
| 传播载体 | 场景 |
|---|---|
HTTP header(traceparent/tracestate) |
服务间调用 |
| MQ message headers | 异步链路(否则链路在此断掉) |
| 日志 MDC | 让日志能按 traceId 聚合(J02 §5) |
判据:跨线程/跨进程/跨 MQ 之后,traceId 是否还一样? 任何一处断了,后面的调用就是"孤儿 span"。
5. 三个组件各管什么(原文的定位)
| 组件 | 角色 | 现状(2026) |
|---|---|---|
| Zipkin | 追踪后端 + UI:收 span、存、查 | 仍在维护,轻量、适合学习与中小规模 |
| Sleuth | Spring Cloud 的追踪自动配置(生成/传播 traceId) | Spring Boot 3 起不再演进,被 Micrometer Tracing 取代 |
| Micrometer Tracing | Boot 3 的追踪门面,桥接 Brave / OpenTelemetry | 当前推荐(J02) |
| OpenTelemetry | 厂商中立的 API/SDK/协议(OTLP) | 跨语言首选;与 Zipkin 可互通 |
为什么必须说清这层:大量旧文写"加 spring-cloud-starter-sleuth 即可",在 Boot 3 上根本拉不起来——这是版本陷阱,J02 会给出正确依赖。
6. 一个最小的心智模型:追踪 = 结构化日志 + 树
Span 的字段(最小集):
traceId / spanId / parentId
name(操作名,如 "GET /orders/{id}")
startTime / duration
status(OK / ERROR)/ error 信息
attributes(http.method、db.statement、peer.service ...)
判断"这个系统适不适合上追踪"(A-560 §14 的四场景,任务版):
| 场景 | 建议 |
|---|---|
| 单体 + 单库 | 结构化日志足够,追踪收益低 |
| 3 个以上服务互相调用 | 值得上,排障收益立刻可见 |
| 只在学分布式概念 | 用 Zipkin + 两个服务即可,别上全套 |
| 已有 Prometheus 指标 | 追踪补"跨服务因果",两者互补 |
7. 常见误区
| 误区 | 纠正 |
|---|---|
| "有日志就不需要追踪" | 日志能证明"发生了什么",追踪证明"谁调用了谁、各花多久" |
| "traceId 打到日志里就够了" | 还需要 span 的父子关系,否则无法定位耗时归属 |
| "采样 100% 才准" | 高流量下 1%–10% + 错误全采,足够定位(A01) |
| "追踪能替代 profiling" | 追踪是跨进程视角,方法级热点要靠 profiling |
8. 自测
- 画一次你熟悉的请求的 span 树(至少 5 个 span,标出 parent)。
- 你的异步任务(MQ/线程池)里,
traceId还在吗?不在 → J02 §5。 - 一次请求产生 800 个 span,最可能的原因是什么?
9. 下一篇
S16-J02 · 接入实战:Spring Boot 3 + Micrometer Tracing + Zipkin —— 给出能跑起来的依赖、配置、采样与"traceId 进日志"的完整步骤。