3. 分布式追踪核心概念:Trace、Span、SpanContext、Baggage

在分布式系统中,一个用户请求往往需要跨越多个微服务、数据库、消息队列和第三方 API 才能完成。要快速定位这类请求的故障根因,必须理解分布式追踪的四个核心抽象:Trace、Span、SpanContext 和 Baggage。它们是 Jaeger 等追踪系统的数据模型基石,也是事故响应时解读调用链的“语言”。

3.1 Trace:端到端的请求全景图

Trace(追踪)代表一个完整的、端到端的请求在分布式系统中的执行路径。它由一组具有相同 Trace ID 的 Span 组成,逻辑上描述了一次事务从入口到出口的全过程。

  • 唯一标识:每个 Trace 由一个全局唯一的 TraceID 标识(通常为 128 位或 64 位整数)。
  • 生命周期:从客户端发起请求开始,到最终响应返回结束。
  • 故障定位价值:在事故响应中,通过 Trace 可以快速判断故障影响范围——是整个 Trace 超时,还是某个下游服务导致整体延迟飙升。
事故响应要点:当收到“请求超时”告警时,首先查找对应 TraceID。如果 Trace 中所有 Span 都慢,问题可能在入口层或网络;如果只有某个 Span 异常,则故障大概率在该 Span 对应的服务内。

3.2 Span:追踪的最小工作单元

Span(跨度)是分布式追踪中描述一次具体操作的最小工作单元。每个 Span 代表一个服务内部完成的单一操作,例如一次数据库查询、一次 RPC 调用或一段业务逻辑处理。

Span 属性 说明 故障定位用途
OperationName 操作名称,如 HTTP POST /api/order 快速识别操作类型
SpanID 当前 Span 的唯一标识 区分同一 Trace 内的不同操作
ParentSpanID 父 Span 的 ID,用于构建调用层级 还原调用链上下游关系
StartTime / Duration 开始时间戳和持续时长 计算延迟、发现慢操作
Tags 键值对元数据,如 http.status_code=500 记录错误码、异常类型等关键信号
Logs 时间戳 + 结构化日志事件 记录异常堆栈、关键变量值
最佳实践:在事故响应中,优先关注 Duration 异常高的 Span,以及 Tags 中包含 error=true 或 http.status_code >= 500 的 Span。这些是根因定位的“第一现场”。

3.3 SpanContext:跨进程的追踪上下文

SpanContext(跨度上下文)是跨进程传递追踪信息的载体。当服务 A 调用服务 B 时,必须将当前 Trace 的上下文信息通过 RPC 头部或消息队列属性传递给下游,否则两个服务之间的 Span 将无法关联到同一个 Trace。

SpanContext 包含以下核心数据:

  • TraceID:全局唯一追踪 ID。
  • SpanID:当前 Span 的 ID。
  • Baggage:用户自定义的键值对(见 3.4 节)。
  • TraceFlags:追踪标志位,如是否采样。
常见陷阱:在事故响应中,如果发现 Trace 不完整(例如只有入口 Span,没有下游 Span),通常是因为 SpanContext 未正确传递。检查 RPC 框架是否自动注入 uber-trace-id 或 traceparent 头部。
Trace 与 Span 层级结构示例 Trace (TraceID: abc123) Root Span: HTTP POST /api/order (SpanID: A, Duration: 1200ms) Child Span: 用户服务 - 校验 (SpanID: B, Duration: 50ms) Child Span: 订单服务 - 创建订单 (SpanID: C, Duration: 800ms) Child Span: 数据库 INSERT (SpanID: D, Duration: 750ms, error=true) 故障定位线索:Span D 耗时 750ms 且标记 error=true,是根因嫌疑最大的 Span

3.4 Baggage:跨服务传递的上下文数据

Baggage(行李)是 SpanContext 中一组用户自定义的键值对,会随着 Trace 的传播自动传递到所有下游 Span。与 Tags 不同,Baggage 是跨进程传递的,而 Tags 仅存在于当前 Span 所在进程。

特性 Tags Baggage
作用域 当前 Span 所在进程 整个 Trace 的所有 Span
传递方式 不跨进程 通过 SpanContext 跨进程传递
典型用途 记录错误码、延迟、SQL 语句 传递用户 ID、请求来源、A/B 测试标签
性能影响 低(仅本地存储) 中(序列化到每个 RPC 头部)
事故响应价值 定位具体错误原因 关联用户维度、灰度版本等业务上下文
事故响应实战:在变更窗口期间,如果某个 Trace 出现故障,通过 Baggage 中的 deploy.version 或 feature.flag 可以快速判断该请求是否命中刚上线的灰度版本,从而缩小根因范围。

3.5 核心概念关系总结

四个核心概念的关系可以概括为:一个 Trace 包含多个 Span,每个 Span 携带 SpanContext,SpanContext 中可附加 Baggage。在 Jaeger UI 中,Trace 以瀑布图形式展示,每个横条代表一个 Span,横条长度表示 Duration,颜色表示服务或状态。

Trace / Span / SpanContext / Baggage 关系 Trace (TraceID: 全局唯一) Span A (SpanID: A1) Operation: 用户服务 - 校验 Span B (SpanID: B1) Operation: 订单服务 - 创建 SpanContext: TraceID + SpanID + Baggage SpanContext: TraceID + SpanID + Baggage Baggage 示例: { "user_id": "u123", "deploy_version": "v2.1.0" }

3.6 事故响应中的概念应用

在变更窗口事故响应场景中,理解这四个概念能帮助 SRE 快速建立排查路径:

  1. 通过 TraceID 锁定故障请求:从告警或日志中提取 TraceID,在 Jaeger 中打开完整 Trace 瀑布图。
  2. 扫描 Span 列表:按 Duration 降序排列,找到耗时最长的 Span;检查 Tags 中是否有 error=true 或异常状态码。
  3. 检查 SpanContext 传递:如果 Trace 不完整,确认上下游服务是否正确传递了 uber-trace-id 头部。
  4. 利用 Baggage 做业务关联:如果 Baggage 中携带了 deploy.version,对比正常 Trace 与故障 Trace 的版本差异。
Jaeger UI 操作提示:在 Trace 详情页,点击任意 Span 可查看其 Tags 和 Logs;使用“Find…”功能可以快速搜索包含特定 Tag 或 Baggage 的 Span,大幅提升排查效率。