3. 分布式追踪基础概念:Trace、Span、SpanContext、TraceId、SpanId、Parent-Child关系、采样率
在深入存储选型之前,必须统一团队对分布式追踪核心数据模型的理解。值班台作为故障响应的一线工具,其追踪数据的结构直接决定了查询效率、关联分析能力以及存储成本。本节将拆解构成一次完整追踪的原子单元。
3.1 核心概念全景
分布式追踪的本质是记录一次请求在多个服务、多个进程间的完整传播路径。以下六个概念构成了追踪数据模型的基石:
| 概念 | 定义 | 类比(快递物流) | 关键属性 |
|---|---|---|---|
| Trace | 一次完整请求的生命周期,跨多个服务 | 一个包裹从发货到签收的全程 | 全局唯一 TraceId |
| Span | Trace 中的一个工作单元,代表一次操作 | 包裹经过的每个 | SpanId、操作名、开始/结束时间 |
| SpanContext | 跨进程传递的追踪上下文 | 包裹上的运单标签 | TraceId、SpanId、Baggage |
| TraceId | Trace 的全局唯一标识 | 运单号 | 16/32 字节,全局唯一 |
| SpanId | Span 的唯一标识 | 内部工单号 | 8 字节,Span 内唯一 |
| Parent-Child | Span 之间的因果关系 | 上一站到下一站的依赖 | Child Span 记录 ParentSpanId |
值班台视角: 在故障排查时,Trace 是“案件卷宗”,Span 是“笔录条目”,SpanContext 是“案件编号”。没有清晰的 Parent-Child 关系,就无法还原调用链的因果逻辑。
3.2 Trace 与 Span:追踪的骨架与血肉
Trace 是一个有向无环图(DAG),由多个 Span 通过 Parent-Child 关系连接而成。每个 Trace 有且仅有一个根 Span(Root Span),代表请求的入口点。
Span 是追踪的最小工作单元,包含以下核心字段:
- 操作名(Operation Name):如
HTTP GET /api/orders、MySQL query - 开始时间戳 & 持续时间:精确到微秒
- 标签(Tags):键值对,记录元数据(如
http.status_code=200) - 日志(Logs):时间戳 + 结构化消息,记录事件(如异常堆栈)
- SpanContext:用于跨进程传播的上下文
// 典型 Span 结构(JSON 表示)
{
"traceId": "abc123def456",
"spanId": "span001",
"parentSpanId": "root_span",
"operationName": "HTTP GET /api/users",
"startTime": 1710000000123456,
"duration": 150000, // 微秒
"tags": {
"http.method": "GET",
"http.status_code": 200,
"peer.service": "user-service"
},
"logs": [
{
"timestamp": 1710000000123500,
"fields": {
"event": "cache.miss",
"key": "user:123"
}
}
]
}
3.3 TraceId 与 SpanId:唯一性保障
这两个 ID 是追踪数据的“主键”,决定了存储系统的索引效率和查询性能。
| 属性 | TraceId | SpanId |
|---|---|---|
| 生成时机 | 请求入口(网关/负载均衡) | 每个 Span 创建时 |
| 长度(W3C 标准) | 16 字节(128 bit),hex 编码 32 字符 | 8 字节(64 bit),hex 编码 16 字符 |
| 生成算法 | 随机数 + 时间戳组合 | 随机数 / 自增序列 |
| 全局唯一性 | 必须全局唯一 | Span 内唯一即可 |
| 存储索引 | 主索引,用于聚合 Trace | 辅助索引,用于关联查询 |
选型陷阱: 部分存储系统(如 Elasticsearch)对 128 bit 的 TraceId 索引性能较差。如果 TraceId 采用 32 字符 hex 字符串,建议使用
keyword 类型并启用 eager_global_ordinals;如果采用二进制存储,需确认后端是否支持。
3.4 Parent-Child 关系:构建调用链拓扑
Parent-Child 关系通过 parentSpanId 字段实现。每个 Span(除根 Span 外)必须记录其父 Span 的 SpanId。这种关系形成了三种典型的调用模式:
- 顺序调用(Sequential):服务 A 调用服务 B,B 返回后再调用 C。Span 呈链式结构。
- 并行调用(Parallel):服务 A 同时调用服务 B 和 C。B 和 C 的 Span 共享同一个 ParentSpanId。
- 嵌套调用(Nested):服务 A 调用服务 B,B 内部又调用 C。形成深度嵌套的树形结构。
3.5 SpanContext:跨进程的追踪信使
SpanContext 是分布式追踪的“粘合剂”,负责在服务之间传递追踪状态。它通常通过 HTTP 头、gRPC 元数据或消息队列属性进行传播。
W3C Trace-Context 标准 定义了两种传播头:
traceparent:携带 TraceId、SpanId 和 TraceFlags(采样标记)。格式:00-{traceId}-{spanId}-{flags}tracestate:携带供应商特定的扩展数据,用于兼容不同追踪系统
// traceparent 示例
// 版本- TraceId(32 hex) - SpanId(16 hex) - Flags(2 hex)
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
// tracestate 示例
tracestate: congo=t61rcWkgMzE,rojo=00f067aa0ba902b7
值班台实践: 在微服务网关层统一注入
traceparent 头,确保所有下游服务都能继承同一个 TraceId。如果发现某个服务“断链”(Trace 不完整),优先检查该服务是否正确解析和传递了 SpanContext。
3.6 采样率:成本与完整性的平衡
采样率决定了“记录多少比例的请求”。在值班台场景中,采样策略直接影响故障复现能力和存储成本。
常见采样策略对比:
| 策略 | 原理 | 适用场景 | 值班台推荐度 |
|---|---|---|---|
| 固定比率采样 | 按固定百分比(如 10%)采样 | 低流量、稳定系统 | ★★☆☆☆ |
| 基于速率采样 | 每秒固定采样 N 条 Trace | 高流量、成本敏感 | ★★★☆☆ |
| 基于错误采样 | 100% 采样错误 Trace + 随机采样正常 Trace | 故障排查、SLO 监控 | ★★★★★ |
| 尾部采样(Tail-Based) | 请求完成后,根据结果(延迟、错误)决定是否保留 | 高精度故障分析 | ★★★★☆ |
| 头采样(Head-Based) | 请求入口处决定是否采样,后续继承 | 简单、低延迟 | ★★★☆☆ |
3.7 采样率对存储选型的影响
采样率直接决定了存储系统的写入吞吐和磁盘占用。在值班台场景中,需要根据流量预估存储规模:
- 低采样(< 1%):适合高流量生产环境(如每秒 10 万请求),存储成本可控,但可能遗漏偶发故障。
- 中采样(1% - 10%):适合大多数微服务系统,兼顾成本与可观测性。
- 高采样(> 10%):仅用于低流量系统或核心链路(如支付、登录)。
- 全采样(100%):仅用于开发/测试环境或合规审计场景。
存储选型公式: 每日 Span 写入量 = QPS × 平均 Span 数/请求 × 采样率 × 86400 秒。例如:QPS=5000,平均 15 Span/请求,采样率 5%,则每日 Span 量 ≈ 5000 × 15 × 0.05 × 86400 = 3.24 亿 Span。以此评估存储系统的写入性能和压缩比。