2、分布式追踪基础:分布式追踪的概念、Trace/Span/Context Propagation核心术语、OpenTelemetry标准介绍
2.1 分布式追踪:从“黑盒”到“白盒”的跨越
在单体应用时代,一次用户请求的生命周期被限制在单一进程内。通过日志和单机 profiling 工具,工程师可以相对容易地定位性能瓶颈。然而,当应用拆分为数十甚至数百个微服务后,一个请求会穿越多个服务、数据库、消息队列和第三方 API。传统的监控手段(如单机 CPU、内存指标)只能告诉你“系统出问题了”,却无法回答“是哪个服务、哪段代码拖慢了整个请求”。
分布式追踪(Distributed Tracing)正是为解决这一难题而生。它通过为每个请求注入一个全局唯一的 Trace ID,并记录请求在跨服务调用链中每个环节的耗时与状态,从而将一次分布式请求的完整路径还原为一条可视化的“调用链”。
2.2 核心术语:Trace、Span 与 Context Propagation
理解分布式追踪,必须掌握三个核心概念:Trace、Span 和 Context Propagation。它们构成了追踪数据的骨架与灵魂。
2.2.1 Trace(追踪)
Trace 代表一次完整的请求或事务在分布式系统中的全生命周期。它由一个全局唯一的 Trace ID 标识。一个 Trace 由一组具有因果关系的 Span 组成,这些 Span 共同描述了请求从入口到出口的完整路径。
2.2.2 Span(跨度)
Span 是追踪的最小工作单元,代表系统中一个有名称、有开始时间和结束时间的操作。每个 Span 包含以下关键属性:
- Span ID:当前 Span 的唯一标识。
- Parent Span ID:父 Span 的 ID,用于构建 Span 之间的父子关系(树形结构)。
- Trace ID:所属 Trace 的 ID。
- Operation Name:操作名称,例如
HTTP GET /api/users或SELECT * FROM orders。 - Start / End Timestamp:操作的开始和结束时间。
- Attributes:键值对形式的元数据,用于附加业务或技术信息(如 HTTP 状态码、数据库语句)。
- Events:带时间戳的日志事件,用于记录 Span 生命周期内的关键点(如异常、缓存命中)。
- Status:操作结果状态(OK / ERROR / UNSET)。
2.2.3 Context Propagation(上下文传播)
Context Propagation 是分布式追踪的“神经系统”。它负责将 Trace ID 和 Span ID 等信息,随着请求从一个服务传递到下一个服务。常见的传播方式包括:
- HTTP Headers:通过
traceparent、tracestate等标准 Header 传递。 - 消息队列 Headers:在 Kafka、RabbitMQ 等消息的元数据中注入。
- gRPC Metadata:通过 gRPC 的 Metadata 机制传递。
2.3 核心术语对比表
| 术语 | 英文 | 定义 | 类比(现实世界) |
|---|---|---|---|
| 追踪 | Trace | 一次完整请求的端到端路径,由 Trace ID 唯一标识 | 一次快递从寄件到签收的完整物流轨迹 |
| 跨度 | Span | 追踪中的单个工作单元,记录一个操作的开始、结束和元数据 | 物流轨迹中的每一个节点(揽收、分拣、运输、派送) |
| 上下文传播 | Context Propagation | 将 Trace ID 和 Span ID 等信息跨服务边界传递的机制 | 快递单号在物流各环节之间的传递 |
| 跨度 ID | Span ID | 每个 Span 的唯一标识 | 每个物流节点的唯一编号 |
| 父跨度 ID | Parent Span ID | 标识当前 Span 的父 Span,用于构建树形结构 | 当前物流节点的上一个节点编号 |
2.4 OpenTelemetry 标准:统一可观测性的“普通话”
在 OpenTelemetry(简称 OTel)出现之前,分布式追踪领域存在多种标准(如 OpenTracing、OpenCensus、Jaeger、Zipkin 等),导致厂商锁定和集成成本高昂。OpenTelemetry 由 CNCF 孵化,旨在提供一套厂商中立、统一的 API、SDK 和协议,用于生成、采集和导出遥测数据(Traces、Metrics、Logs)。
2.4.1 OpenTelemetry 核心组件
- API:定义 Traces、Metrics、Logs 的数据模型和操作接口,与具体实现解耦。
- SDK:提供 API 的默认实现,包括采样、处理、导出等能力。
- Collector:一个独立的代理服务,用于接收、处理、聚合和导出遥测数据。支持多种接收器(Receiver)和导出器(Exporter)。
- Exporter:将遥测数据发送到后端存储或分析平台(如 Jaeger、Prometheus、Datadog、Grafana Tempo)。
- Instrumentation Libraries:为常见框架和库(如 Spring Boot、Express、gRPC、Redis)提供自动埋点能力,无需手动修改业务代码。
2.4.2 OpenTelemetry 的优势
| 特性 | 说明 |
|---|---|
| 厂商中立 | 一次接入,可切换任意后端(Jaeger、Zipkin、Datadog、Grafana 等) |
| 统一标准 | 融合 OpenTracing 和 OpenCensus,避免重复投资 |
| 多信号支持 | 同时支持 Traces、Metrics、Logs,实现真正的可观测性三大支柱 |
| 自动埋点 | 通过 Instrumentation Libraries 自动注入,降低接入成本 |
| 活跃社区 | CNCF 孵化项目,社区贡献活跃,生态丰富 |
2.4.3 OpenTelemetry 数据模型示例(Trace)
以下是一个使用 OpenTelemetry API 创建 Span 的代码示例(Java 语言):
// 1. 获取 Tracer
Tracer tracer = openTelemetry.getTracer("com.example.service");
// 2. 创建一个 Span(自动成为当前 Span 的子 Span)
Span span = tracer.spanBuilder("processOrder")
.setAttribute("order.id", "12345")
.setAttribute("payment.method", "credit_card")
.startSpan();
// 3. 将 Span 放入当前上下文
try (Scope scope = span.makeCurrent()) {
// 执行业务逻辑
Thread.sleep(100);
// 记录事件
span.addEvent("payment.processed");
} catch (Exception e) {
span.setStatus(StatusCode.ERROR, "Payment failed: " + e.getMessage());
span.recordException(e);
} finally {
// 4. 结束 Span
span.end();
}
finally 块中调用 span.end(),否则 Span 将永远不会被导出,导致追踪数据丢失。使用 try-with-resources 或 Scope 模式可以自动管理 Span 的生命周期。