Skip to content

入门:trace/span 模型与 OpenTelemetry 集成

基于 Jaeger 1.x + OpenTelemetry · 核于 2026-08

速查

  • 是什么:Jaeger(耶格)是 CNCF 毕业的开源分布式追踪系统(Uber 2017 开源),解决微服务下「一个请求经过 N 个服务,哪里慢/哪里错」的难题。它通过 OpenTelemetry SDK 给每个请求打 traceID,记录每段处理(span),组成调用树(trace),可视化请求流转。
  • trace:一次请求的完整链路,唯一 traceID 标识。一个 trace 是一棵 span 树(从入口服务到最深层调用)。
  • span:trace 中的一个处理段——一个服务/操作的处理单元,含操作名、起止时间、tags(属性)、logs、parent span 引用。多个 span 按 parent/child 关系组成 trace 树。
  • 上下文传播(Context Propagation):traceID 随请求跨服务传递——通过 HTTP header(W3C Trace Context 的 traceparent、Jaeger 的 uber-trace-id、Zipkin 的 B3)或 RPC metadata,让下游服务知道「我属于哪个 trace、我的 parent span 是谁」。
  • OpenTelemetry(OTel):CNCF 的可观测性数据标准(trace/metrics/logs 统一采集),Jaeger 是 OTel trace 的主要后端之一。OTel SDK 埋点 → 导出器(exporter)发到 Jaeger。
  • 采样(sampling):高流量场景不可能全采 trace(成本爆炸),需采样。头部采样(入口决定,简单但可能丢根因)vs 尾部采样(结束时按条件决定,精准但延迟);策略有概率(probabilistic,如 1%)、速率限制(ratelimiting,如 10 traces/s)。
  • 存储后端:Jaeger 支持 Cassandra、Elasticsearch、内存(测试用)——存 trace 数据 + 属性索引,按 traceID 或属性查找。
  • Zipkin 兼容:Zipkin 是更早的开源追踪系统(Twitter 2012),现基本并入 OTel 生态;Jaeger 支持接收 Zipkin 格式数据,迁移友好。
  • 与 Tempo 的对比:Tempo(Grafana 系)按 traceID 查找(不索引属性省存储),Jaeger 原生支持属性检索(service/operation/tags,强但贵)。按场景选:要强属性检索选 Jaeger,要省存储+Grafana 联动选 Tempo。

一、Jaeger 是什么:分布式追踪的事实标准

微服务架构下,一个用户请求可能经过:网关 → 用户服务 → 订单服务 → 库存服务 → 支付服务 → 数据库。其中某一步慢或错,如何定位?没有分布式追踪,只能 SSH 到每个服务 grep 日志盲目拼接——效率极低。Jaeger 解决这个问题:

用户请求 → 网关(span A,10ms)
            ↓ 传播 traceID(HTTP header)
         → 用户服务(span B,50ms)

         → 订单服务(span C,200ms)
            ├─→ 库存服务(span D,80ms)
            └─→ 支付服务(span E,100ms)← 慢!
                  └─→ DB(span F,30ms)

Jaeger 把这棵 span 树可视化:一眼看到支付服务 span E 耗时最长(瓶颈)
  • trace 是树:一个 trace 由多个 span 按 parent/child 组成树,根 span 是请求入口。
  • 每个 span 记录:操作名(service/operation)、起止时间(耗时)、tags(属性如 http.method=GET、error=true)、logs(事件)、parent span ID。
  • 可视化:Jaeger UI 把 trace 树画成瀑布图(甘特图),每条 span 一行,长度反映耗时——一眼看到瓶颈 span。

二、trace 与 span:核心数据模型

trace(追踪)

  • 一次请求的完整链路,唯一 traceID(如 4bf92f3577b34da6a3ce929d0e0e4736)标识。
  • 一棵 span 树(从根 span 到叶子 span)。
  • 整体耗时 = 根 span 的起止时间差。

span(跨度)

  • trace 中的一个处理段——一个服务/操作的处理单元。
  • 每个 span 有:①spanID(唯一);②parent spanID(父 span,根 span 无 parent);③traceID(所属 trace);④operation name(如 GET /api/order);⑤start time + duration;⑥tags(属性 key-value,如 http.status_code=500error=true);⑦logs(事件,如异常栈);⑧service name(产生该 span 的服务)。

树结构示例

trace (traceID: abc123)
├─ span A: gateway GET /checkout (root, 380ms, parent: 无)
│  ├─ span B: user-svc getUser (50ms, parent: A)
│  ├─ span C: order-svc createOrder (280ms, parent: A)
│  │  ├─ span D: inventory-svc deduct (80ms, parent: C)
│  │  └─ span E: payment-svc charge (180ms, parent: C)  ← 瓶颈
│  │     └─ span F: db INSERT payment (30ms, parent: E)
  • 瀑布图:Jaeger UI 把这棵树画成甘特图,横轴是时间,每条 span 一行,子 span 缩进在父 span 下。
  • 瓶颈定位:耗时最长的 span(如 span E 180ms)是优化重点。

三、上下文传播:traceID 跨服务传递

traceID 必须随请求跨服务传递,下游服务才知道「我属于哪个 trace、我的 parent 是谁」:

网关(创建 traceID=abc123, spanID=A)
  → 请求用户服务,HTTP header 加:
     traceparent: 00-abc123-A-01          (W3C Trace Context)
     // 或 uber-trace-id: abc123:A:0:1   (Jaeger 格式)
     // 或 X-B3-TraceId: abc123           (Zipkin B3 格式)
用户服务(读 header,得知 traceID=abc123, parent=A)
  → 创建自己的 span B(spanID=B, parent=A)
  → 请求订单服务时继续传播 traceID + 自己的 spanID 作为 parent
  • W3C Trace Contexttraceparent 头):业界标准,OTel 默认用,跨厂商兼容。
  • Jaeger 格式uber-trace-id):Jaeger 原生格式。
  • Zipkin B3X-B3-TraceId):Zipkin 格式,广泛兼容。
  • 传播媒介:HTTP header、RPC metadata(gRPC)、消息队列消息属性(Kafka headers)——只要能带元数据的通道都能传播。

四、OpenTelemetry:埋点与导出标准

OpenTelemetry(OTel)是 CNCF 的可观测性数据采集标准,统一 trace/metrics/logs:

应用代码
  ↓ OTel SDK(自动/手动埋点,创建 span、传播上下文)
  ↓ OTel Collector(可选,中转处理、批量、过滤)
  ↓ 导出(exporter)
Jaeger / Tempo / Datadog / Zipkin(后端,存+查询+可视化)
  • 一次埋点,多处导出:OTel SDK 是厂商中立的——换后端只改 exporter 配置,不用改业务代码。
  • 自动埋点:OTel 提供 instrumentation library,自动埋点常见库(HTTP server/client、DB driver、Kafka)——无需改业务代码。
  • 手动埋点:业务关键逻辑(如自定义函数)用 tracer.startSpan("my-operation") 手动创建 span。
  • Jaeger 作后端:Jaeger 原生支持 OTel 协议(OTLP),是 OTel trace 的主流后端之一。

五、采样:控制上报量

高流量场景不可能全采 trace(每请求一个 trace,存储与处理成本爆炸),需采样:

策略含义优缺点
概率采样(probabilistic)按概率(如 1%)采简单,但稀有错误可能漏
速率限制(ratelimiting)每秒最多 N 个 trace平滑流量,但突发流量可能丢
远程采样(remote)中心化配置采样率,动态调整灵活,可按服务/端点不同
尾部采样(tail sampling)请求结束后按条件采(如错误/慢)精准(保证采到错误/慢),但延迟+复杂
  • 头部采样(入口决定):简单,但入口采样 1% 意味着 99% 请求连错误 trace 都没有。
  • 尾部采样(OTel Collector 实现):等请求结束,按条件(is error? latency > 1s?)决定是否采——保证采到错误与慢请求,代价是要缓存所有 trace 到结束(内存+延迟)。

六、与 Zipkin/Tempo 的关系

  • Zipkin:Twitter 2012 开源的早期追踪系统,现基本并入 OTel 生态(用 OTel SDK 埋点,Zipkin 作后端)。Jaeger 支持接收 Zipkin 格式数据,迁移友好。
  • Tempo(Grafana 系):设计取舍与 Jaeger 相反——Tempo 不索引属性,按 traceID 查找(省存储约 Jaeger 1/N),早期不支持属性检索(只能 traceID),新版 TraceQL 补齐属性检索。Jaeger 原生支持属性检索(service/operation/tags)但存储贵。
  • 选型:要强属性检索(不知道 traceID 时按 service/错误查)选 Jaeger;要省存储+已上 Grafana 栈选 Tempo。

下一步

理解了 trace/span 模型与 OTel 集成后,下一步深入两个核心维度——分布式追踪(span 树结构 + 上下文传播 + OTel SDK 埋点导出 + Jaeger 后端架构)与采样与对比(头部/尾部采样 + Zipkin 并入 + Tempo 检索/存储取舍)。