Skip to content

三支柱与 OTLP 详解:Metrics、Logs、Traces 的统一

基于 OpenTelemetry 1.x(2026-05 CNCF 毕业) · 核于 2026-08

速查

  • 三支柱数据模型:①Metrics——时序数值,由 Meter API 创建(Counter 递增计数、Histogram 分布、Gauge 瞬时值、UpDownCounter 可增可减);②Logs——结构化事件,由 Logger API 发射(带 severity、body、attributes、trace_id 关联);③Traces——span 树,由 Tracer API 创建(span 有 trace_id/span_id/parent_span_id/name/起止时间/attributes/status)。
  • 三支柱共享 trace_id:这是 OTel 的精髓。一个请求的 trace_id 会同时关联到它的 trace span、metric 数据点(exemplar)、log 记录——从 metric 异常跳到 trace、从 trace span 跳到 log,形成完整排障链路。
  • OTLP(OpenTelemetry Protocol):统一传输协议。①数据模型用 protobuf 定义(Metrics/Logs/Traces 各有规范结构);②传输支持 OTLP/gRPC(默认)和 OTLP/HTTP(POST protobuf 或 JSON);③后端无关——后端实现 OTLP 接收端即可消费,这是终结厂商锁定的根基。
  • Instrumentation 两种方式:①自动埋点——加载 instrumentation library 自动拦截主流框架(HTTP/gRPC/Express/Kafka/Redis/DB 驱动),零代码改动;②手动埋点——用 OTel API 显式创建业务 span/metric/log。生产实践:自动埋点覆盖通用调用 + 手动埋点补充业务语义。
  • API vs SDK@opentelemetry/api 只定义接口(不产生数据,零依赖,业务代码只依赖它);@opentelemetry/sdk-node 等是实现(真正产生数据、配置导出)。库代码只用 API,应用入口配 SDK——这样库不绑死具体实现。
  • Resource(资源):描述数据来源的属性集(host.name、service.name、service.version、deployment.environment、cloud.provider),附加在所有遥测数据上,标识「哪个服务哪个环境产生的」。在 SDK 启动时配置一次,全局生效。
  • Context Propagation(上下文传播):trace_id/span_id 跨服务跨进程传递。W3C Trace Contexttraceparent header:00-<trace-id>-<span-id>-<flags>)是标准,OTel 默认用它。A 调 B 时 OTel 自动把 trace_id 注入请求 header,B 的 OTel 自动提取——B 的 span 挂到 A 的 trace 树上。
  • Sampler(采样器):决定哪些 trace/span 被记录。高频服务全量记录开销大,用采样(如 ParentBased/TraceIDRatioBased/AlwaysOn/AlwaysOff)控制数据量。Metrics 通常不采样(全量),Traces 常采样(如 10%)。
  • Exemplar(范例):Metrics 的数据点可以关联一个 trace——当指标出现高延迟异常值时,exemplar 指向那个高延迟请求的 trace,从 metric 直接跳到 trace 排障。

一、三支柱的数据模型

Metrics(指标):时序数值

OTel 的 Metrics API(Meter)提供四种仪器:

仪器行为典型用途
Counter只增不减(累加)请求总数、错误总数、字节发送量
UpDownCounter可增可减队列长度、活跃连接数
Histogram分布(值 + 桶)延迟分布(P50/P90/P99)、响应大小
Gauge瞬时值(可涨可跌)CPU 使用率、温度、内存
javascript
const meter = metrics.getMeter('order-service');
const requestCounter = meter.createCounter('orders.total', { description: '订单总数' });
const latencyHistogram = meter.createHistogram('orders.duration', { unit: 'ms' });

requestCounter.add(1, { status: 'success', region: 'cn' });
latencyHistogram.record(150, { endpoint: '/api/order' });
  • 属性(attributes/labels):每个数据点带多维标签,可切片聚合(按 status/region/endpoint)。
  • 与 Prometheus 的关系:OTel 的 Histogram 概念和 Prometheus 一致(桶 + 总和 + 计数),OTel Collector 可把 OTel metric 转成 Prometheus exposition format。

Logs(日志):结构化事件

OTel 的 Logs API(Logger)发射结构化日志记录,带:severity(级别)、body(正文)、attributes(结构化字段)、trace_id/span_id(关联追踪)

javascript
const logger = logs.getLogger('order-service');
logger.emit({
  severity: SeverityNumber.ERROR,
  body: '订单处理失败',
  attributes: { orderId: 123, reason: 'insufficient_stock' },
  // trace_id 自动从当前 context 关联(如有)
});
  • 日志关联 trace:OTel 的精髓——日志自动带上当前请求的 trace_id,在 trace 视图里能看到对应日志,反之亦然。
  • 成熟度:Logs 信号在多数语言 SDK 2024-2025 陆续 GA(Metrics/Traces 更早 GA)。

Traces(追踪):span 树

OTel 的 Traces API(Tracer)创建 span——一个操作单元,有 trace_id(整条链路)、span_id(本段)、parent_span_id(父段)、name、起止时间、attributes、status、events:

javascript
const tracer = trace.getTracer('order-service');
const span = tracer.startSpan('process_order', { attributes: { orderId: 123 } });
try {
  const childSpan = tracer.startSpan('charge_payment');  // 子 span
  await chargePayment(order);
  childSpan.end();
} finally {
  span.end();
}
  • span 树:一个请求的多个服务/操作形成树(根 span 是入口),通过 parent_span_id 串联。
  • attributes:span 的结构化属性(如 orderId、http.method、db.statement),用于检索过滤。
  • events:span 内的离散事件(如「缓存未命中」「重试第 2 次」)。

二、三支柱联动:trace_id 贯穿

OTel 的精髓是三支柱共享 trace_id,形成排障闭环:

Metrics 告警:orders.duration P99 突增到 2000ms

   │ exemplar 指向慢请求的 trace_id

Traces 定位:该请求的 span 树 → 发现 DB 查询 span 耗时 1800ms

   │ span 的 trace_id 关联 logs

Logs 细节:DB 查询的日志 → 「慢查询,缺索引」


根因:缺索引 → 加索引修复

没有 trace_id 关联,三支柱各自孤立——看 metric 知道「有问题」、看 trace 知道「卡在哪」、看 log 知道「为什么」,三者串联才能高效排障。

三、OTLP:统一传输协议

OTLP 让三支柱用同一协议传输,是后端无关的根基:

维度说明
数据模型protobuf 定义 Metrics/Logs/Traces 的规范结构
传输OTLP/gRPC(默认,TCP 长连接)或 OTLP/HTTP(POST protobuf 或 JSON)
端口gRPC 默认 4317,HTTP 默认 4318
后端接入后端实现 OTLP receiver 即可消费(或用 Collector 转码)
  • 为什么统一协议重要:以前 Metrics 走 Prometheus pull、Logs 走 Syslog/Fluentd、Traces 走 Jaeger thrift——三套。OTLP 一套搞定,应用只发 OTLP,Collector 扇出到任意后端。
  • OTLP/JSON:HTTP + JSON 格式,方便调试(curl 能直接发)和不支持 gRPC 的环境(如某些 Serverless)。

四、Instrumentation:自动 vs 手动

自动埋点(Automatic Instrumentation)

加载 instrumentation library,零代码改动接入主流框架:

javascript
// Node.js 入口注册 instrumentation
import { NodeSDK } from '@opentelemetry/sdk-node';
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter(),
  instrumentations: [
    new HttpInstrumentation(),      // 自动埋 HTTP 调用
    new ExpressInstrumentation(),   // 自动埋 Express 路由
    new PgInstrumentation(),        // 自动埋 PostgreSQL 查询
  ],
});
sdk.start();
  • 覆盖范围:HTTP/gRPC 服务器与客户端、Web 框架(Express/Koa/Spring/Django)、DB 驱动(pg/mysql/redis)、消息队列(Kafka/RabbitMQ)、云 SDK。
  • 优势:零业务代码改动,快速接入,覆盖通用调用链。
  • 局限:只能埋「框架级」调用,业务语义(如「处理支付」)要手动。

手动埋点(Manual Instrumentation)

用 OTel API 在业务代码里显式创建 span/metric/log:

javascript
// 业务 span:自动埋点覆盖不到的语义
const span = tracer.startSpan('business.validate_order');
span.setAttribute('order.amount', order.amount);
try {
  validateOrder(order);
} catch (e) {
  span.recordException(e);
  span.setStatus({ code: 2, message: e.message });
  throw e;
} finally {
  span.end();
}
  • 何时手动:业务关键操作(下单/支付/风控)、自动埋点覆盖不到的逻辑、需要业务属性(orderId)的 span。
  • 生产实践:自动埋点打基础(覆盖通用调用)+ 手动埋点补业务语义(关键流程的 span/metric)。

五、API vs SDK:库与应用的分工

角色依赖职责
库代码(如 npm 包)只依赖 @opentelemetry/api用 API 创建 span/metric(接口,不产生数据)
应用入口配置 SDK(如 @opentelemetry/sdk-node注册 exporter、配 resource、加载 instrumentation(真正产生+导出数据)
  • 为什么这么分:库只依赖 API(零依赖、轻量),不绑死具体 SDK 实现。应用在入口决定用哪个 SDK、发哪个后端——库的埋点代码在 SDK 注入后自动生效。这就是「库不绑后端」的设计。

六、Resource 与 Context 传播

  • Resource(资源):在 SDK 启动时配置,标识数据来源:
javascript
const resource = new Resource({
  'service.name': 'order-service',
  'service.version': '1.2.0',
  'deployment.environment': 'production',
  'host.name': os.hostname(),
});

这个 resource 附加在该应用产生的所有 metrics/logs/traces 上——后端能按 service/environment 切片聚合。

  • Context Propagation(上下文传播):trace_id 跨服务传递。OTel 默认用 W3C Trace Contexttraceparent header):
A 服务调 B 服务:
  A 的 OTel 自动在请求 header 注入:
    traceparent: 00-<trace-id>-<span-id>-01
  B 的 OTel 自动从 header 提取 trace-id
  B 创建的 span 的 parent_span_id = A 传来的 span-id
  → B 的 span 挂到 A 的 trace 树上,形成完整链路
  • W3C 标准traceparent 是 W3C 推荐标准(2020),主流框架/语言都支持,保证跨语言跨服务传播追踪上下文。
  • Baggage:另一个 W3C 标准,用于跨服务传播业务键值对(如 tenant-id),不进 trace 但随请求流转。

下一步

三支柱与 OTLP 讲完后,下一步是Collector 与生态采用——Collector 的接收-处理-导出架构、与 Prometheus/Jaeger 的关系、2026 CNCF 毕业的意义。