入门: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=500、error=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 Context(
traceparent头):业界标准,OTel 默认用,跨厂商兼容。 - Jaeger 格式(
uber-trace-id):Jaeger 原生格式。 - Zipkin B3(
X-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 检索/存储取舍)。