2. OpenTelemetry 核心概念:Trace、Span、Metrics、Logs、Context Propagation、Baggage
在分布式系统与异步任务编排场景中,可观测性依赖于一套标准化的数据模型与传播机制。OpenTelemetry 定义了六大核心概念,它们共同构成了从数据采集、关联到分析的基础框架。理解这些概念是进行故障排查与部署调优的前提。
2.1 Trace 与 Span:请求的完整路径与工作单元
Trace 代表一个请求或事务在分布式系统中经过的完整路径。它由多个 Span 组成,每个 Span 代表路径中的一个具体工作单元(如一次 RPC 调用、一个数据库查询、一个异步任务步骤)。
Span 是 Trace 的原子构建块,包含以下关键属性:
- Span ID:唯一标识当前 Span。
- Trace ID:标识整个 Trace,所有相关 Span 共享此 ID。
- Parent Span ID:指向父 Span,形成层级关系。
- Span Name:描述操作名称(如
process_order)。 - Start / End Timestamp:记录操作耗时。
- Attributes:键值对元数据(如
user.id、queue.name)。 - Status:成功或错误状态。
2.2 Metrics:聚合的量化指标
Metrics 提供系统在时间维度上的聚合测量,用于监控健康状态、容量规划和性能趋势。OpenTelemetry 支持三种主要 Metric 类型:
| Metric 类型 | 说明 | 典型场景 |
|---|---|---|
| Counter | 单调递增的计数器,只增不减 | 请求总数、任务失败次数 |
| Histogram | 对观测值进行分桶统计,可计算百分位数 | 任务处理延迟 P50/P99 |
| Gauge | 可上下波动的瞬时值 | 当前队列深度、活跃工作线程数 |
Metrics 不包含单个请求的上下文,但可以与 Trace 通过 Exemplar 机制关联,将极端延迟的 Trace ID 嵌入到 Histogram 桶中。
2.3 Logs:结构化的事件记录
Logs 是带有时间戳的结构化或非结构化文本记录。OpenTelemetry 推动日志从纯文本向 结构化日志 演进,要求每条日志包含 timestamp、severity、body 和 attributes。
在异步任务编排中,日志必须携带 Trace ID 和 Span ID,才能实现日志与 Trace 的关联。例如:
{
"timestamp": "2025-03-21T10:30:00.123Z",
"severity": "ERROR",
"body": "Task processing failed after 3 retries",
"attributes": {
"trace_id": "abc123def456",
"span_id": "span789",
"task_id": "task-001",
"queue": "high-priority"
}
}
LogContext 或 MDC 自动注入 Trace ID,避免手动拼接。
2.4 Context Propagation:跨边界的上下文传递
Context Propagation 是 OpenTelemetry 的“神经系统”,负责将 Trace、Span、Baggage 等信息在服务之间、线程之间、异步回调之间传递。它通过 Propagator 组件实现,支持多种协议格式:
- W3C Trace Context:标准 HTTP 头
traceparent和tracestate。 - gRPC Metadata:在 gRPC 调用中传递。
- Message Headers:在 Kafka、RabbitMQ 等消息队列中传递。
- Thread Local / AsyncLocal:在进程内线程切换时保持上下文。
在异步任务编排中,上下文传播的常见断裂点包括:
- 线程池切换:任务提交到线程池后丢失父 Span 上下文。
- 消息队列消费:生产者与消费者之间未正确传递 Trace ID。
- 定时器/延迟任务:回调执行时上下文已过期。
2.5 Baggage:跨服务传递的业务上下文
Baggage 是一组键值对,随 Trace 在整个请求链路中传播。与 Span Attributes 不同,Baggage 会跨越服务边界,用于传递业务级信息(如用户 ID、实验分组、请求优先级)。
Baggage 的使用原则:
- 轻量:只传递少量关键业务上下文,避免携带大量数据。
- 安全:不传递敏感信息(如密码、Token),因为 Baggage 可能被中间服务记录。
- 显式:在代码中通过
Baggage.current()读取,通过Baggage.builder()设置。
// 设置 Baggage
Baggage.current().toBuilder()
.put("user.role", "premium")
.put("experiment.id", "exp-2025-03")
.build()
.makeCurrent();
// 在远端服务读取
String role = Baggage.current().getEntryValue("user.role");
2.6 六大概念关系图
下图展示了 Trace、Span、Metrics、Logs、Context Propagation 和 Baggage 之间的协作关系:
2.7 概念对比与选型指南
| 概念 | 数据粒度 | 跨服务传播 | 主要用途 | 异步任务场景价值 |
|---|---|---|---|---|
| Trace | 请求级 | 是(通过 Propagator) | 追踪完整请求路径 | 定位任务编排中的延迟瓶颈和失败环节 |
| Span | 操作级 | 否(仅本地) | 记录单个操作耗时与状态 | 分析每个异步步骤的执行时间与错误 |
| Metrics | 聚合级 | 否(本地聚合) | 监控系统健康与趋势 | 监控队列积压、任务吞吐量、重试率 |
| Logs | 事件级 | 否(但可携带 Trace ID) | 记录详细事件与异常堆栈 | 排查任务失败的具体原因和上下文 |
| Context Propagation | 元数据 | 是(核心功能) | 传递 Trace/Span/Baggage | 确保异步链路不断裂,跨队列/线程保持关联 |
| Baggage | 业务级 | 是(随 Trace 传播) | 传递业务上下文 | 传递任务优先级、用户分群,影响调度策略 |