4. OpenTelemetry 标准介绍

在构建支付订单微服务时,可观测性不能依赖厂商绑定的 Agent 或私有协议。OpenTelemetry(简称 OTel)应运而生,它是一套厂商中立、开源、统一的遥测数据采集与导出标准,已成为 CNCF 的孵化项目,也是云原生可观测性的事实标准。

核心价值:一次埋点,任意后端。开发者只需按照 OTel API 编写 instrumentation 代码,数据即可导出到 Jaeger、Zipkin、Prometheus、Datadog 等任意兼容后端,无需切换 SDK 或重写埋点。

4.1 OpenTelemetry 是什么

OpenTelemetry 是一组 API、SDK、工具和协议的集合,用于从应用程序中生成、采集、处理和导出遥测数据(Traces、Metrics、Logs)。它由 OpenTracing 和 OpenCensus 合并而来,解决了过去可观测性碎片化的问题。

维度 说明
Traces(链路) 记录一次请求在分布式系统中的完整调用路径,包含 Span 及其父子关系
Metrics(指标) 聚合型数值数据,如请求延迟 P99、QPS、错误率、CPU 使用率
Logs(日志) 带时间戳的结构化或非结构化文本记录,可与 Trace ID 关联
课程聚焦:本课程重点使用 OTel Traces 实现分布式链路追踪,同时结合 Metrics 做性能监控。Logs 部分仅做关联说明,不深入展开。

4.2 核心组件:API / SDK / Collector

OpenTelemetry 架构分为三层,每一层职责清晰,可独立替换或扩展。

OpenTelemetry 核心组件架构 API 层 TracerProvider MeterProvider LoggerProvider SDK 层 SpanProcessor Sampler Exporter Collector 层 Receiver Processor Exporter 说明 • API 定义接口,不依赖具体实现;SDK 提供默认实现,可配置采样、批处理、导出。 • Collector 作为独立代理或网关,接收、处理、转发遥测数据,支持多后端。 Jaeger Prometheus Datadog

4.2.1 API 层

  • TracerProvider:创建 Tracer,Tracer 负责生成 Span(链路追踪的基本单元)。
  • MeterProvider:创建 Meter,Meter 负责生成 Instrument(如 Counter、Histogram)。
  • LoggerProvider:创建 Logger,负责生成 LogRecord。

4.2.2 SDK 层

  • SpanProcessor:控制 Span 的生命周期回调,如批处理、异步导出。
  • Sampler:采样策略,决定哪些请求被记录(如 AlwaysOn、TraceIdRatioBased)。
  • Exporter:将遥测数据序列化并发送到 Collector 或后端(如 OTLP、Jaeger、Zipkin)。

4.2.3 Collector 层

  • Receiver:接收来自 SDK 或其他 Collector 的数据(支持 OTLP、Jaeger、Prometheus 等协议)。
  • Processor:数据过滤、批处理、属性修改、采样决策。
  • Exporter:将处理后的数据发送到后端存储或分析系统。
架构决策提示:在微服务规模较小时,SDK 可直接导出到后端;但在支付订单系统中,强烈建议引入 Collector 作为中间层,实现统一采样、数据脱敏、多后端分发,避免 SDK 直连后端带来的配置爆炸和网络抖动问题。

4.3 与 NestJS 的集成方式

NestJS 集成 OpenTelemetry 主要有两种方式:自动埋点(Auto-instrumentation)和手动埋点(Manual instrumentation)。实际生产环境通常两者结合使用。

集成方式 原理 适用场景
自动埋点 通过 Node.js 的 require 钩子或模块补丁,自动拦截 HTTP、gRPC、数据库等操作 快速接入,覆盖通用组件(Express、TypeORM、Redis、Kafka)
手动埋点 在业务代码中显式调用 OTel API 创建 Span、添加属性/事件 自定义业务逻辑、支付核心链路、关键事务追踪
混合模式 自动埋点覆盖基础设施,手动埋点增强业务语义 支付订单系统推荐方案

4.3.1 自动埋点集成步骤

  1. 安装 OTel Node.js SDK 及自动埋点包:@opentelemetry/sdk-node、@opentelemetry/auto-instrumentations-node。
  2. 在应用启动入口(如 main.ts 之前)初始化 SDK,注册自动埋点模块。
  3. 配置 OTLP Exporter 指向 Collector 或后端地址。
// tracing.ts - 自动埋点初始化
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';

const sdk = new NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'payment-order-service',
  }),
  traceExporter: new OTLPTraceExporter({
    url: 'http://otel-collector:4318/v1/traces',
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();

4.3.2 手动埋点集成步骤

  1. 安装 @opentelemetry/api,在 NestJS 服务或拦截器中获取 Tracer。
  2. 使用 tracer.startSpan() 创建自定义 Span,包裹关键业务逻辑。
  3. 在 Span 上添加属性(如订单 ID、支付金额)和事件(如扣款成功、回调接收)。
// payment.service.ts - 手动埋点示例
import { trace, Span } from '@opentelemetry/api';

@Injectable()
export class PaymentService {
  private readonly tracer = trace.getTracer('payment-service');

  async processPayment(orderId: string, amount: number): Promise<boolean> {
    const span: Span = this.tracer.startSpan('payment.process', {
      attributes: {
        'order.id': orderId,
        'payment.amount': amount,
      },
    });

    try {
      // 模拟支付处理
      const result = await this.deductBalance(orderId, amount);
      span.setStatus({ code: SpanStatusCode.OK });
      span.addEvent('payment.deduct.success', { 'order.id': orderId });
      return result;
    } catch (error) {
      span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
      span.addEvent('payment.deduct.failed', { 'error': error.message });
      throw error;
    } finally {
      span.end();
    }
  }
}
课程实践:在后续章节中,我们将基于 NestJS 的 Interceptor 和 Decorator 实现声明式链路追踪,让手动埋点更优雅,避免业务代码被可观测性逻辑侵入。

4.4 集成架构总览

下图展示了支付订单系统中,NestJS 微服务与 OpenTelemetry 的完整集成拓扑:

NestJS 微服务 + OpenTelemetry 集成拓扑 NestJS 服务 A 支付订单服务 NestJS 服务 B 账户余额服务 OTel SDK 自动埋点 手动埋点 SpanProcessor OTLP Exporter OTel Collector Receiver (OTLP) BatchProcessor 采样/脱敏 多后端 Exporter Jaeger Prometheus 集成要点 • 每个 NestJS 服务内嵌 OTel SDK,通过自动埋点捕获 HTTP/RPC/DB 调用。 • 所有服务将 Traces 和 Metrics 通过 OTLP 协议发送到统一的 Collector,由 Collector 负责采样、脱敏和分发。
本章小结:OpenTelemetry 通过 API/SDK/Collector 三层解耦,让 NestJS 微服务可以低成本接入分布式链路追踪和指标监控。自动埋点覆盖通用组件,手动埋点增强业务语义,Collector 作为统一网关保障数据治理。下一章我们将实战配置 NestJS 自动埋点,并验证链路数据是否正确上报。