2. OpenTelemetry 核心概念回顾:Trace、Span、Metrics、Logs 与 Context 传播

在深入 Mock 依赖隔离与性能优化之前,必须重新校准对 OpenTelemetry(OTel)核心数据模型的理解。OTel 并非简单的“链路追踪工具”,而是一个统一的可观测性数据面标准。本章将聚焦于三大信号(Trace、Metrics、Logs)及其底层支撑机制——Context 传播,为后续的 Mock 注入与性能压测建立共同语言。

2.1 三大信号与 Span 的基石地位

OTel 将可观测性数据归纳为三种信号(Signal),它们共享相同的元数据模型与传播机制:

信号 核心单元 主要用途 Mock 隔离关注点
Traces Span 请求端到端路径与延迟分布 Span 创建/结束的 Mock 注入点
Metrics Instrument(Counter/Histogram) 聚合统计(QPS、P99、错误率) 指标采集频率与 Mock 数据隔离
Logs LogRecord 结构化事件与异常详情 日志上下文与 Trace 关联

其中 Span 是 OTel 数据模型的基石。一个 Trace 由一个或多个 Span 组成,每个 Span 代表一个具有开始时间、结束时间、属性(Attributes)、事件(Events)和状态(Status)的工作单元。

关键认知: 在 Mock 依赖隔离场景中,我们主要 Mock 的是 Span 的创建、结束与属性注入过程,而非 Metrics 或 Logs 的聚合逻辑。理解 Span 的生命周期是性能优化的第一步。

2.2 Span 的完整生命周期与属性结构

一个 Span 从创建到结束经历以下阶段,每个阶段都可能成为 Mock 注入的切入点:

  1. Span 创建(Start):从 Context 中提取父 Span,生成新的 SpanContext,分配 TraceId 与 SpanId。
  2. 属性注入(Attributes):添加业务标签(如 HTTP 方法、状态码、数据库语句)。
  3. 事件记录(Events):记录带时间戳的异常或关键日志。
  4. Span 结束(End):记录结束时间,计算耗时,将 Span 导出到 Processor。

以下是一个典型的 Span 结构示例(Java SDK 伪代码):

Span span = tracer.spanBuilder("processOrder")
    .setSpanKind(SpanKind.SERVER)
    .setAttribute("order.id", "12345")
    .setAttribute("payment.method", "credit_card")
    .start();

try (Scope scope = span.makeCurrent()) {
    // 业务逻辑
    Thread.sleep(100);
} catch (Exception e) {
    span.recordException(e);
    span.setStatus(StatusCode.ERROR);
} finally {
    span.end();
}
Mock 隔离提示: 在单元测试或集成测试中,我们通常 Mock tracer.spanBuilder() 返回的 Span 实例,使其不真正创建 ID、不触发导出,从而消除 I/O 开销。但必须保留 makeCurrent() 的 Context 传播行为,否则下游代码无法获取正确的 Trace 上下文。

2.3 Context 传播:连接所有信号的隐形管道

Context 传播是 OTel 最容易被低估的核心机制。它负责在进程内(线程、协程)和进程间(HTTP、gRPC、消息队列)传递 Trace 上下文、Baggage 以及自定义上下文值。

Context 传播的典型流程如下:

Context 传播流程(进程内 + 进程间) 上游服务 Span A (Server) Context 注入 W3C TraceContext 下游服务 Span B (Client) 线程 A Span A 活跃 线程 B(异步) Span A 传播 线程 C(回调) Span B 创建 说明: 进程间通过 W3C TraceContext 头部传播;进程内通过 ThreadLocal / AsyncLocal 传播。Mock 时必须保留 Context 传播链。

2.4 Metrics 与 Logs 的上下文关联

Metrics 和 Logs 虽然不直接参与 Trace 的树形结构,但它们通过 Attributes 和 Context 与 Trace 建立关联:

  • Metrics 关联:OTel 的 Exemplar 机制允许在 Histogram 中嵌入 TraceId/SpanId,实现“指标可追溯”。
  • Logs 关联:LogRecord 可以携带 SpanContext,将日志行直接挂载到对应的 Span 下。
性能陷阱: 在 Mock 隔离测试中,如果 Metrics 的采集器(如 PeriodicReader)仍然在后台线程中真实运行,即使 Trace 被 Mock,Metrics 的聚合与导出仍会产生 CPU 和内存开销。必须同时 Mock 或禁用 Metrics 的导出管道,才能获得真实的性能基线。

2.5 核心概念对比总结

概念 数据模型 传播方式 Mock 隔离难度 性能影响权重
Trace / Span 树形结构,ID 驱动 Context 传播 中(需保留 Context) 高(Span 创建/结束频繁)
Metrics 聚合数据点 独立导出管道 低(可直接禁用) 中(聚合计算 + 导出 I/O)
Logs 结构化记录 通常独立 低(可关闭) 低(异步写入为主)
Context 传播 隐式上下文 ThreadLocal / 协议头 高(必须保留) 低(仅指针传递)