分布式追踪详解:Trace、Span 与上下文传播的工作原理

分布式追踪通过 Trace 与 Span 记录请求在微服务间的完整流转路径,是微服务排障的核心技术。本文讲透 Trace ID、Span、埋点、上下文传播、采样等核心概念,以及如何用观测云落地分布式追踪。

最佳实践
分布式追踪详解:Trace、Span 与上下文传播的工作原理封面

分布式追踪是一种记录请求在分布式系统中完整流转路径的技术:请求每经过一个环节就产生一个 Span,所有 Span 由同一个 Trace ID 串联成调用树——在单体架构里,看本地日志就够;而在微服务架构里,只有分布式追踪能回答「这个请求为什么慢、错误是从哪个服务冒出来的」。

核心要点速览

  • Trace = 一次请求的完整旅程;Span = 旅程中的一个环节(一次调用、一条 SQL);
  • Trace ID 全局唯一,Span 之间通过父子关系构成调用树;
  • 上下文传播(Context Propagation)是跨进程串联 Trace 的关键机制;
  • 全量采集成本高昂,生产环境通常配合采样策略。

为什么需要分布式追踪?

微服务架构下,一个用户请求可能依次经过网关、鉴权服务、订单服务、库存服务、数据库与消息队列。当用户投诉「下单很慢」时:

  • 看每个服务自己的日志:都正常,因为每个环节只慢了 100ms;
  • 看接口总耗时:2 秒,但不知道耗在哪。

这就是分布式追踪要解决的问题——局部正常 ≠ 全局正常,只有完整的调用链视角才能暴露累积延迟与跨服务错误传播。

分布式追踪是如何工作的?

以一次下单请求为例:

  1. 请求到达入口服务,探针生成全局唯一的 Trace ID 和第一个 Span;
  2. 入口服务调用订单服务时,把 Trace ID 与当前 Span ID 通过 HTTP 头(如 traceparent)传递下去——这就是上下文传播;
  3. 每个下游服务基于收到的上下文创建子 Span,记录自己的操作名、起止时间、状态与属性;
  4. 所有 Span 上报到后端,按 Trace ID 组装成调用树,用瀑布图/火焰图呈现。

分布式追踪的核心概念

Trace 与 Trace ID

Trace 是一次请求的完整记录;Trace ID 是其全局唯一标识,也是串联日志、指标的关键字段——在日志中注入 Trace ID 后,链路和日志就能互相跳转。

Span

Span 是 Trace 的基本单元,包含:操作名(如 GET /orders)、开始与结束时间、状态(OK/ERROR)、父子关系。一个 Span 代表一个工作单元:一次 HTTP 调用、一条 SQL、一个内部函数。

埋点(Instrumentation)

让应用产生 Span 的过程。分两类:自动埋点(Java Agent、eBPF,零代码改动)与手动埋点(用 SDK 为关键业务逻辑补充 Span)。

Span 属性(Attributes)与事件

属性是附加在 Span 上的键值对(如 http.status_code=200、db.statement=...),是后续检索与分析的维度;Span 事件记录 Span 生命周期中的时间点信息(如异常抛出)。

上下文传播

把 Trace 上下文(traceparent/tracestate 或 B3 头)跨进程传递的机制。异步场景(消息队列)同样需要在消息头中携带上下文,否则链路会断。断链是落地分布式追踪最常见的坑,详见《OpenTelemetry 上下文传播》。

采样(Sampling)

全量采集所有请求的 Trace 在流量大时成本不可接受。采样策略(头部采样、尾部采样)在「保留代表性数据」与「控制成本」之间取得平衡,详见《OpenTelemetry 采样详解》。

后端分析平台

Span 数据的存储与分析端:提供服务拓扑、链路检索、耗时分析。观测云 APM 即承担这一角色。

分布式追踪对可观测性的意义

链路数据把「点状」的日志和指标组织成「线状」的请求故事:指标告诉你错误率升高,链路告诉你是哪个依赖引入的,日志告诉你具体报了什么错。三者以 Trace ID 为纽带形成排障闭环。

生态与标准

当前事实标准是 OpenTelemetry(CNCF 项目,统一了 OpenTracing 与 OpenCensus),其 OTLP 协议已成为链路数据交换的通用语言;采用其他探针时,应分别核对其接收协议、版本及字段映射。eBPF 则提供了零侵入的链路采集新路径。

接入并验证一条跨服务请求

以观测云作为追踪后端时,先选择一个入口及其下游服务做验证:

  1. 为两端应用配置 OTel SDK 或兼容的自动探针,按 OpenTelemetry 采集器文档 设置 DataKit 接收地址和协议。DDTrace 使用自己的接入路径,不混用 OTLP 配置。
  2. 发出一个测试请求,确认入口和下游 Span 的 Trace ID 一致、父子关系正确,再检查错误与耗时。
  3. 将相同的 trace_id 写入并采集应用日志,在 链路详情 核对关联日志;多索引场景还要匹配 service、env、version 对应的索引映射。
  4. 验证通过后,再扩大服务范围,并按流量调整采样与保留策略。

常见问题(FAQ)

Q:异步消息(Kafka)场景链路会断吗? 会断如果不在消息头中注入上下文。应分别核对所用消息客户端与探针的支持范围,并用一条生产者到消费者的消息验证。

Q:老系统没法改代码能做链路追踪吗? 两条路:Java 等语言用 Agent 自动埋点(零代码);或者用 eBPF 方案在内核层采集服务间调用(覆盖度略低于埋点但零侵入)。

Q:采样会不会漏掉关键的出错请求? 尾部采样策略可以先缓存再决策,优先保留错误与高延迟的 Trace;头部采样则按比例随机。选择策略时要核对 SDK、Collector 与后端各自承担的采样环节。

Q:分布式追踪和服务网格(Istio)的追踪有什么区别? 服务网格追踪在网络代理层生成 Span,零应用侵入但缺少应用内部细节;埋点追踪包含应用内部逻辑。两者可互补使用。

系列阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台