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 架构分为三层,每一层职责清晰,可独立替换或扩展。
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 自动埋点集成步骤
- 安装 OTel Node.js SDK 及自动埋点包:
@opentelemetry/sdk-node、@opentelemetry/auto-instrumentations-node。 - 在应用启动入口(如
main.ts之前)初始化 SDK,注册自动埋点模块。 - 配置 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 手动埋点集成步骤
- 安装
@opentelemetry/api,在 NestJS 服务或拦截器中获取 Tracer。 - 使用
tracer.startSpan()创建自定义 Span,包裹关键业务逻辑。 - 在 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 的完整集成拓扑:
本章小结:OpenTelemetry 通过 API/SDK/Collector 三层解耦,让 NestJS 微服务可以低成本接入分布式链路追踪和指标监控。自动埋点覆盖通用组件,手动埋点增强业务语义,Collector 作为统一网关保障数据治理。下一章我们将实战配置 NestJS 自动埋点,并验证链路数据是否正确上报。