4. OpenTelemetry 核心概念:TracerProvider、Span、SpanContext、Sampler、Exporter、Instrumentation 库

在 BFF 层实施全链路监控,首先需要理解 OpenTelemetry 的六大核心概念。它们构成了数据产生、处理、关联与导出的完整链路。下面逐一拆解其职责与协作关系。

核心原则: OpenTelemetry 通过 Instrumentation 库 自动或手动埋点,由 TracerProvider 统一管理 Span 的创建,每个 Span 携带唯一的 SpanContext 用于跨进程传播,Sampler 决定哪些 Span 被保留,最终由 Exporter 将数据发送到后端。
OpenTelemetry 六大核心概念协作关系 BFF 应用 / 服务 Instrumentation 库 TracerProvider Sampler Span SpanContext Exporter 后端 (Jaeger/Zipkin) 数据流方向:BFF 应用 → Instrumentation 库 → TracerProvider → Sampler → Span → SpanContext → Exporter → 后端

4.1 TracerProvider — 追踪的入口与工厂

TracerProvider 是 OpenTelemetry 追踪系统的核心入口。它负责创建 Tracer 实例,并持有全局配置,包括 Sampler、Exporter 和资源信息(Resource)。在 BFF 层,通常每个服务进程只初始化一个全局 TracerProvider。

职责 说明
创建 Tracer 通过 getTracer(name, version) 返回指定名称的 Tracer 实例
管理配置 统一设置 Sampler、SpanProcessor、Exporter 和 Resource
生命周期 应用启动时初始化,关闭时优雅刷新未导出的 Span
BFF 实践建议: 在 BFF 入口文件(如 app.ts)中尽早初始化 TracerProvider,并设置 service.name 为 BFF 服务名,便于后续区分不同 BFF 实例的追踪数据。

4.2 Span — 追踪的基本工作单元

Span 代表一个操作的时间片段,例如一次 HTTP 请求、一个数据库查询或一个内部函数调用。每个 Span 记录操作名称、开始/结束时间戳、属性(Attributes)、事件(Events)和状态(Status)。

  • Span 层级: 通过父子关系形成追踪树(Trace Tree)。根 Span 代表整个请求,子 Span 代表内部子操作。
  • Span 生命周期: Start → 添加属性/事件 → End。
  • 关键属性: http.method、http.url、http.status_code、error 等。
// Node.js 示例:手动创建 Span
const tracer = trace.getTracer('bff-tracer');
const span = tracer.startSpan('POST /api/order');
span.setAttribute('http.method', 'POST');
span.setAttribute('http.url', '/api/order');
// ... 执行业务逻辑
span.end();

4.3 SpanContext — 跨进程传播的身份证

SpanContext 是 Span 的不可变标识信息,包含 TraceId 和 SpanId,以及可选的 TraceFlags 和 Tracestate。它通过 HTTP 头(如 traceparent)在服务间传播,实现跨 BFF 与上游/下游服务的链路关联。

字段 长度 说明
TraceId 16 字节(128 位) 全局唯一追踪 ID,标识整条请求链路
SpanId 8 字节(64 位) 当前 Span 的唯一标识
TraceFlags 1 字节 追踪选项,如是否采样
Tracestate 可变 厂商自定义的追踪上下文数据
常见陷阱: 在 BFF 层调用下游微服务时,必须手动或通过 Instrumentation 库将 SpanContext 注入到 HTTP 请求头中,否则链路会在 BFF 处断裂,无法形成完整追踪树。

4.4 Sampler — 采样决策者

Sampler 决定哪些 Span 被记录并导出。在高并发 BFF 场景下,全量采样会带来巨大的存储和性能开销,因此采样策略至关重要。

  • AlwaysOn: 采样所有 Span,适合低流量或调试环境。
  • AlwaysOff: 关闭所有采样,适合禁用追踪。
  • TraceIdRatioBased: 基于 TraceId 的哈希值按比例采样,例如 10% 采样率。
  • ParentBased: 继承父 Span 的采样决策,确保整条链路一致。
// 配置 10% 采样率
const sampler = new TraceIdRatioBasedSampler(0.1);
const provider = new BasicTracerProvider({
  sampler: sampler,
});

4.5 Exporter — 数据导出通道

Exporter 负责将 Span 数据发送到后端存储或分析系统(如 Jaeger、Zipkin、Prometheus、OTLP Collector)。BFF 层通常使用 BatchSpanProcessor 配合 Exporter,以批量、异步方式导出,减少对请求路径的性能影响。

Exporter 类型 协议 适用后端
OTLP Exporter gRPC / HTTP OpenTelemetry Collector
Jaeger Exporter Thrift / gRPC Jaeger
Zipkin Exporter JSON / Thrift Zipkin
Console Exporter 标准输出 调试日志

4.6 Instrumentation 库 — 零侵入埋点

Instrumentation 库 为常见框架和库提供自动埋点能力,无需手动修改业务代码。在 BFF 层,最常用的 Instrumentation 库包括:

  • @opentelemetry/instrumentation-http: 自动追踪 HTTP 客户端和服务器请求。
  • @opentelemetry/instrumentation-express: 自动追踪 Express 路由处理。
  • @opentelemetry/instrumentation-grpc: 自动追踪 gRPC 调用。
  • @opentelemetry/instrumentation-fetch: 自动追踪浏览器 Fetch API。
// 注册 HTTP 和 Express 自动埋点
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express');

registerInstrumentations({
  instrumentations: [
    new HttpInstrumentation(),
    new ExpressInstrumentation(),
  ],
});
BFF 最佳实践: 优先使用 Instrumentation 库实现自动埋点,覆盖 HTTP 入口/出口和数据库调用;仅在需要记录业务关键路径(如订单创建、支付回调)时,手动创建自定义 Span 补充细节。
Span 生命周期与父子关系(BFF 请求示例) Root Span: GET /api/user Child Span: 验证 Token Child Span: 查询用户 DB Child Span: 调用下游订单服务 时间轴 t0 t1 t2 t3 Span 关键属性 • trace_id: 全局唯一 • span_id: 当前 Span 标识 • parent_span_id: 父 Span 标识

4.7 核心概念总结

六大概念在 BFF 全链路监控中各司其职:

概念 一句话职责 BFF 关注点
TracerProvider 追踪系统的全局工厂 初始化时机、Resource 配置
Span 记录一个操作的时间片段 属性、事件、状态、父子关系
SpanContext 跨进程传播的追踪标识 HTTP 头注入与提取
Sampler 控制采样率,降低存储开销 高并发下选择 ParentBased + 比例采样
Exporter 将 Span 数据发送到后端 BatchSpanProcessor + OTLP 协议
Instrumentation 库 自动埋点,减少手动代码 覆盖 HTTP、Express、gRPC 等