Skip to content

链路追踪原理

链路追踪的核心是把一次跨服务的请求,通过统一的 Trace / Span / Segment 模型还原成完整调用链。理解这些概念的生成、传播与合并过程,才能看懂 Trace 页面上的每一行数据,也才能在遇到断链时知道去哪排查。

Trace / Span / Segment

SkyWalking 在 Dapper 模型基础上引入 **Segment(段)**这一层概念,用于组织单个进程内的数据上报。

概念含义
Trace一次分布式请求的完整调用路径,由 traceId 唯一标识
SpanTrace 中的一段操作,例如一次 HTTP Client Call 或 SQL Query
Segment某个进程内产生并上报的一组 Span

Segment 与 Trace/Span 的关系:一次调用进入一个进程后,该进程内产生的所有 Span 被打包成一个 Segment 上报给 OAP;OAP 再把这些跨进程的 Segment 按 traceId 合并成完整 Trace。

text
Trace (traceId = T1)
├── Segment A(进程 A,含 Span A1, A2)
│     └── 发起对 B 的调用(携带 T1)
├── Segment B(进程 B,含 Span B1)
│     └── 发起对 DB 的调用(携带 T1)
└── Segment C(进程 C,含 Span C1)

Span 的关键字段

一个 Span 至少包含:

字段作用
traceId所属链路标识
spanId / parentSpanId本 Span 及父 Span 的 ID,用于建树
operationName(Segment 名)如 HTTP /api/order、SQL select
startTime / endTime / duration起止与耗时
component(组件)例如 HTTP、JDBC、Redis
peer(对端地址)下游地址,如 db:3306
tags / logs附加信息,如 URL、SQL、错误堆栈

OAP 据此把 Span 按父子关系还原成树,并统计每个 Span 的耗时。

进程内上下文传播

同一进程/线程内,Span 通过 ThreadLocal(ContextManager) 传递当前追踪上下文,不落网络:

text
进入进程(Segment 开始)
   └► ThreadLocal 保存当前 Span 上下文
        └► 方法 A(Span A)─► 方法 B(Span B) 子 Span 链式嵌套
        └► 方法结束,从 ThreadLocal 弹出
进程结束,打包成 Segment 上报

关键点:

  • 必须成对入栈出栈:Span 打开后要正确关闭,否则 ThreadLocal 泄漏导致链路错乱。
  • 异步不自动传递:线程池、异步回调等场景 ThreadLocal 不会自动带到子线程,需显式传递上下文,否则子线程的 Span 会成为"孤儿 Span"、链路断开。

跨进程上下文传播

跨进程时,发起方把 traceId 等信息写入协议头,接收方读取后续接 Span。

text
服务 A                    服务 B
  │ 生成/续接 traceId        │
  │ 写 traceparent/sw8 到 Header │
  ├─────────────────────────►│ 读取 Header,新建 Segment/Span
  │                          │ 处理,继续向下游传播

传播载体与协议:

载体协议/Header
HTTPsw8(SkyWalking 私有)、W3C traceparent
gRPCgRPC Metadata(sw8 / traceparent
MQ消息 Header(Kafka Header、RocketMQ 消息属性等)
进程内ThreadLocal(ContextManager)

SkyWalking 同时支持自有协议与 W3C Trace Context,跨厂商互通时优先用 W3C。

协议与标准的背景参见 APM / 上下文传播

OAP:Segment 合并(Trace Merging)

OAP 收到大量 Segment 后,按以下方式合并出完整 Trace:

  1. 按 traceId 分桶:把一个 traceId 的所有 Segment 归到一起。
  2. 按 parentSpanId / spanId 建树:还原调用层级。
  3. 计算统计:汇总每个 Span 的耗时、每个 Service/Endpoint 的 RT。
  4. 生成 Topology:根据跨 Service 的调用边,统计服务间调用关系与频率。

一条完整 Trace 的展示依赖所有相关 Segment 都能"对上":只要某个中间服务的 Agent 没上报(例如 Agent 版本不兼容、被采样、断网),该段就会出现缺失或断链。

断链原因排查

在 Trace 页面看到链路"M 形断裂",按此排查:

可能原因检查点
采样导致某些段缺失是否开了采样,两端采样策略是否一致
Header 未传播下游服务是否也接入了 Agent;HTTP/MQ 头名是否被框架改写
异步丢上下文线程池/异步回调是否有异步插件或手动传递
Agent 未接入/上报失败各服务是否都加载了 Agent、OAP 地址是否可达
中间件不透传 header网关、MQ 是否吞掉或重建了头

核心原则:全链路每个参与方都必须是"同一条 traceId、同一个上下文",缺少任何一环都会断链