文档
前言
在单体应用中,bug 排查很简单——看日志、查堆栈。但在微服务中,一个请求可能经过 10+ 个服务,日志分散在各处。分布式追踪让你像单步调试一样追踪整个请求链路。
第一章:核心概念
1.1 Trace vs Span
Trace(追踪)
└── Span A(根 Span - ServiceA)
├── Span B(子 Span - ServiceB)
│ ├── Span C(子 Span - DB 查询)
│ └── Span D(子 Span - Cache 读取)
└── Span E(子 Span - ServiceC)
| 概念 | 含义 | 类比 |
|---|---|---|
| Trace | 一次完整请求的全链路 | 一个完整的"故事" |
| Span | 一个操作单元(含开始/结束时间) | 故事的一个"章节" |
| Trace ID | 全局唯一标识 | 故事编号 |
| Span ID | Span 唯一标识 | 章节编号 |
| Parent Span ID | 父 Span 的 ID | 父章节引用 |
1.2 上下文传播(Context Propagation)
ServiceA: TraceID=abc, SpanID=001
→ HTTP Header: traceparent=00-abc-001-01
→ ServiceB: 提取 TraceID=abc, ParentSpanID=001, 创建 SpanID=002
W3C Trace Context 标准:
traceparent: 00-{trace-id}-{parent-span-id}-{trace-flags}
示例: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
第二章:采样策略
2.1 为什么需要采样
全量追踪会消耗大量存储和计算资源。采样是用少量数据推断整体画像。
2.2 四种采样策略
| 策略 | 工作方式 | 适用场景 |
|---|---|---|
| 常量采样 | 固定比例(如 1%) | 高流量,成本敏感 |
| 概率采样 | 每个 Trace 独立概率 | 一般生产环境 |
| 速率限制 | 每秒最多 N 个 Trace | 控制绝对数据量 |
| 自适应采样 | 低流量全采,高流量降采样 | ✅ 推荐!保证所有服务都有样本 |
# 自适应采样示例(需 jaeger-adaptive-sampling)
# 在 Jaeger Agent 层配置:
# --sampling.strategies-file=/etc/jaeger/sampling.json
2.3 Head-based vs Tail-based
Head-based(SDK 决定):
入口创建 Trace 时决定是否采样
✅ 简单,✅ 无额外开销
❌ 错误 Trace 可能被丢弃
Tail-based(Collector 决定):
所有 Trace 先缓存,根据结果(错误/慢)决定保留
✅ 不错过重要 Trace
❌ 需要缓存和额外处理
第三章:分析 Trace 的方法
3.1 火焰图分析
Jaeger UI 提供火焰图视图,直观显示耗时分布:
service-a.process: ████████████████████████████████████ 570ms
local-computation: ████ 120ms
call-service-b: ██████████████████████ 450ms
db-query: ████████ 250ms ← 瓶颈!
ml-inference: ██████ 200ms
3.2 关键查询
# 查找慢请求
service=service-a AND duration>1s
# 查找错误
service=service-a AND status.code=ERROR
# 查找特定用户
service=service-a AND user.id=42
# 查找特定接口
operation=GET /process AND http.status_code=500
第四章:Jaeger 架构
┌──────────┐ SDK ┌──────────┐
│ 应用 Pod │──OTLP──│ Collector│
│ (SDK) │ └────┬─────┘
└──────────┘ │
┌────┴─────┐
│ Storage │ (ES/Cassandra/Badger)
└────┬─────┘
┌────┴─────┐
│ Query │
└────┬─────┘
16686│ UI
┌────┴─────┐
│ Browser │
└──────────┘
部署模式对比
| 模式 | 组件 | 适用 |
|---|---|---|
| All-in-One | 所有组件打包 | 开发/测试 |
| 分离部署 | Collector + Query + Storage 独立 | 生产 |
| Kubernetes Operator | CRD 声明式管理 | K8s 生产 |
思考题
- 如果 Trace 数据量巨大导致 ES 撑不住,有哪些优化手段(除采样外)?
- Head-based 和 Tail-based 采样各有什么致命的缺点?有没有混合方案?
- 上下文传播如果中断(比如经过一个不支持追踪的中间件),后续 Span 怎么办?
- OpenTelemetry 相比 Jaeger 原生 SDK 有什么优势?为什么现在都推荐 OTel?
下一步
- 学习 OpenTelemetry 三朵金花(Trace + Metrics + Logging)统一采集
- 学习 Jaeger + Elasticsearch 生产部署
- 学习 Jaeger 自适应采样配置