OpenTelemetry 体系介绍:规范、SDK、Collector 架构

大家好。这章咱们聊聊 OpenTelemetry 的体系结构。我早期做链路追踪的时候,各家方案各搞一套,数据格式不互通,SDK 也不一样,后来 OpenTelemetry 出来,总算有了一个统一的方向。说白了,这个体系就三大块:规范(Specification)、SDK(软件开发工具包)、Collector(收集器)。它们怎么配合?咱们往下看。

核心逻辑: 规范定标准,SDK 实现标准并嵌入应用,Collector 负责接收、处理、转发数据。三者缺一不可。

OpenTelemetry 三层体系结构 规范(Specification) 数据模型 · API · 协议 · 语义约定 SDK(语言实现) Java · Go · Python · JS · .NET · C++ · Ruby · Erlang TracerProvider · MeterProvider · Context Propagation · Sampler Collector(独立服务) Receivers(接收器)→ Processors(处理器)→ Exporters(导出器) 支持 OTLP / Jaeger / Prometheus / Zipkin / 自定义 管道配置 · 批处理 · 采样 · 重试 · 内存队列 应用 后端存储 Collector 可部署为 Sidecar 或独立集群,SDK 通过 OTLP 协议发送数据

1. 规范(Specification)—— 一切的基础

没有规范,大家各写各的,就不可能互通。OpenTelemetry 规范定义了三件事:数据模型(Traces、Metrics、Logs 长什么样)、API(开发者怎么调用)、协议(SDK 和 Collector 之间怎么传数据)。

我当年参与过一个多语言微服务项目,Java 和 Go 用的是不同的 APM 厂商,traceId 的编码方式都不一样,联调时对不上。后来我们统一迁到 OpenTelemetry,靠的就是规范里明确的 trace_id 和 span_id 的字节长度和编码规则。嗯,这里要注意:规范本身是不写具体代码的,它是一份文档,目前托管在 github.com/open-telemetry/opentelemetry-specification。

小提示: 规范里的 语义约定(Semantic Conventions) 很重要,比如 HTTP 请求的 http.method、http.url 等 key 都是固定好的。如果你自己乱取名,后续分析工具可能没法识别。

2. SDK —— 开发者的直接战场

SDK 就是规范的具体实现,每种主流语言都有一份。你只需要在你的应用里引入对应的 SDK 包,然后调用 API 打点。我习惯把 SDK 的工作分为三块:

  • TracerProvider: 创建 Tracer,Tracer 创建 Span,Span 就是一次操作的记录。
  • MeterProvider: 创建 Meter,Meter 记录指标(Counter、Histogram 等)。
  • Context Propagation: 把 trace 上下文在进程间(比如 HTTP 请求头)传下去,这是链路不丢的关键。

我曾经踩过一个坑:用 Python SDK 时,默认的 Sampler 是 AlwaysOn,结果业务量上来后 CPU 飙到 90%,后来改成 TraceIdRatioBased(0.1) 才压住。所以啊,生产环境一定要配置采样率。

// 一个最简单的 Java 示例
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
    .setTracerProvider(
        SdkTracerProvider.builder()
            .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder().build()).build())
            .setSampler(Sampler.traceIdRatioBased(0.1))
            .build()
    )
    .build();

Tracer tracer = openTelemetry.getTracer("my-service");
Span span = tracer.spanBuilder("doSomething").startSpan();
try {
    // 你的业务逻辑
} finally {
    span.end();
}

警告: SDK 版本一定要与 Collector 的 OTLP 版本匹配。我见过有人用 v0.7.0 的 SDK 对接 v1.0.0 的 Collector,结果 protobuf payload 解析失败,数据全部丢弃。

3. Collector —— 数据管道的核心枢纽

Collector 是一个独立的代理服务,不侵入业务代码。它接收来自 SDK 或各种 Exporter 的数据,经过管道(Pipeline)处理,再导出到后端。我个人认为这是整个体系中最灵活的部分,因为它允许你在不修改应用的前提下,做数据过滤、采样、重试、甚至转换格式。

Collector 的架构其实很简单:管道由 Receivers、Processors、Exporters 三段组成。数据流是:Receiver 接收 → Processor 处理(可以有多个) → Exporter 发送。

组件 作用 常见实现
Receiver 接收数据,支持多种协议 OTLP Receiver、Jaeger Receiver、Prometheus Receiver
Processor 处理数据,如采样、过滤、批处理、属性修改 Batch Processor、Memory Limiter、Attributes Processor
Exporter 发送到后端存储或分析系统 OTLP Exporter、Jaeger Exporter、Prometheus Exporter、Logging Exporter

配置 Collector 用的是 YAML 文件。举个例子,一个最简的配置:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 1s
    send_batch_size: 1024

exporters:
  otlp:
    endpoint: my-backend:4317
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp]

你想想看,这个配置里我们只启用了 OTLP 接收和导出,中间加了一个 Batch Processor 来合并数据。实际生产环境我还会加上 Memory Limiter 防止 OOM,以及 Filter Processor 丢弃健康检查的 trace。

部署建议: Collector 可以每个节点部署一个(DaemonSet 模式),也可以独立集群部署。小规模用 DaemonSet 简单;大规模推荐独立集群,利用 Processor 做全局采样和降级。

总结一下

OpenTelemetry 的三层体系设计得很巧妙:规范保证了跨语言、跨厂商的兼容性;SDK让开发者零成本接入;Collector提供了数据管道的灵活性。这三层各司其职,缺一不可。我今年在迁移一个遗留系统的监控时,就是用这个体系:先在业务代码里埋 SDK,再部署 Collector 做统一出口,最后迁移后端。整个过程几乎没有停服。