上下文传播与 TraceSegment
SkyWalking 的追踪模型以 TraceContext 保存当前 segment,以 AbstractSpan 表达入口、出口和本地 span;跨服务时把必要上下文编码进协议或请求头。
先给答案:Segment 是本地上下文的提交单元,Span 是其中的时间片
Section titled “先给答案:Segment 是本地上下文的提交单元,Span 是其中的时间片”入口创建 Segment 和根 Span,子调用创建子 Span;跨线程时把 Context 注入任务,跨进程时把传播头写入 HTTP/RPC 消息。下游提取后继续创建自己的 Segment,并通过父子关系或跨进程引用连接回上游。
Segment 批量上报降低网络开销,但也引入本地队列和丢失窗口。链路缺失应分别检查采样是否命中、上下文是否跨线程传递、插件是否增强成功、队列是否积压,以及 OAP 是否正常接收和存储,不能只看 UI。
ContextManager#createEntrySpan -> active segment/span -> createExitSpan -> inject carrier -> remote extract -> continue segment -> span.stop -> segment.finish -> report关键坐标:
ContextManager#createEntrySpan—apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java:91ContextManager#createExitSpan—apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java:130ContextManager#stopSpan—apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java:187TraceContext#newTraceSegment—apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TraceContext.java:73TraceSegment#archive—apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/TraceSegment.java:109AbstractSpan#start—apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java:98AbstractSpan#stop—apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java:145AbstractSpan#inject—apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java:261ContextManager#asyncFinish—apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextManager.java:229
为什么以 segment 为上报单位
Section titled “为什么以 segment 为上报单位”替代方案:每个 span 单独上报。为什么不行:网络请求数量和 OAP 写入压力都会放大,还难以保证同一调用链的局部顺序。选择:一个 segment 聚合本地 span,结束后批量上报。
| 场景 | 现象 | 原因 | 规避 |
|---|---|---|---|
| 异步线程未传播 | Trace 断链 | ThreadLocal 不自动跨线程 | 使用上下文 capture/continuation |
| span 未 stop | segment 不上报 | 生命周期未闭合 | finally 中结束 span |
| TraceId 暴露 | 日志泄露链路信息 | 传播头未保护 | 控制边界并按需脱敏 |
上下文传播应明确“创建、激活、挂起、恢复、关闭”五个动作;异步模型必须提供 continuation,不能只依赖线程局部变量。
面试锚点
- TraceSegment 和 Span 的关系是什么?
- 为什么 segment 结束后再上报?
- 跨线程传播如何避免上下文丢失?