3. OpenTelemetry 标准:架构、SDK 与 Exporter
说到全链路监控,OpenTelemetry 已经是事实标准了。我记得早些年,大家还在为 Jaeger 还是 Zipkin 的选型吵得不可开交,埋点代码也经常绑死在某一个厂商的 SDK 上。后来 CNCF 把 OpenTracing 和 OpenCensus 合并成 OpenTelemetry,业内才算真正统一了思路。
这节课,我带大家把 OpenTelemetry 的骨架拆开看看。说白了,我们只需要搞懂三件事:数据怎么产生的、怎么处理的、怎么送出去的。 对应到组件上,就是 SDK、Collector 和 Exporter。
3.1 OpenTelemetry 的整体架构
先看一张我手绘的架构图,帮你建立全局印象:
这张图展示的,就是一条 Trace 从出生到归档的完整路径。我习惯把 OpenTelemetry 分成三层来看:SDK 层负责采集,Exporter 负责传输,Collector 负责收口。 咱们从最基础的部分往外聊。
3.2 SDK:埋点的灵魂
SDK 是跑在应用进程里的。它决定了你的 Span、Metric 和 Log 能不能被正确地创建出来。我第一次接触 OTel SDK 时,最怕的就是上下文传播出了问题,导致一条 Trace 断成了好几截。
SDK 里核心的组件其实就三个:
- Provider: 全局的工厂,用来创建 Tracer、Meter 这些实例。你在代码开头配置一次就行。
- SpanProcessor: Span 的处理器。它可以对 Span 做过滤、增强、批量打包。生产环境一般用
BatchSpanProcessor,不会每来一个 Span 就发送一次。 - Sampler: 采样器。我个人经验是,线上流量大的系统,一定要设置采样率。要不然扛不住的。可以用
ParentBasedSampler配合固定比例采样。
小提示: 我建议你在开发环境把采样率设成 1.0,但预发布环境立刻调低到 0.1 甚至 0.01。我曾经就因为忘记改采样率,把测试环境的 InfluxDB 直接打爆过——那真是血的教训。
3.2.1 自动埋点 vs 手动埋点
SDK 落地的时候,会面临这个选择。很多人问我:"老师,我能不能全靠自动埋点?" 我的回答是:可以,但不建议全依赖它。
| 对比维度 | 自动埋点(Instrumentation Agent) | 手动埋点(Manual Instrumentation) |
|---|---|---|
| 实现方式 | 通过字节码增强、AOP 改写类库 | 开发者显式调用 API 创建 Span |
| 覆盖范围 | 常见类库(Spring、gRPC、MySQL) | 任意业务代码 |
| 维护成本 | 低,升级 SDK 即可 | 高,需要写业务语义 |
| 业务信息 | 只有 HTTP 方法、URL、状态码等通用信息 | 可以携带订单 ID、用户 ID 等关键字段 |
你看完这个表应该明白了。自动埋点帮你省了 80% 的功夫,但剩下那 20% 往往才是排查问题最需要的信息。比如订单超时了,你光知道请求去了 A 服务、B 服务,这不够。你还要知道是哪个订单、哪个用户——这些必须通过手动埋点加上Span Attributes。
⚠️ 注意: 不要把所有业务字段都塞进 Span。我曾经见过有人把整个请求体 JSON 写进 Attributes……那个 Span 大到可以直接当文档存储。建议只保留 业务 ID、错误码、关键耗时,控制在 5~10 个以内。
3.3 Exporter:数据怎么送出去?
SDK 采集完数据,总不能就地存着。Exporter 就是把数据发往 Collector 或者后端的通道。常见的导出方式有这么几种:
- OTLP Exporter——官方推荐的格式,支持 gRPC 和 HTTP。我基本只用它,因为它是全链路二进制协议,传输效率高。
- Jaeger Exporter——如果你后端是 Jaeger 的旧版本,可以直接用。但 OTel 官方也建议逐渐迁移到 OTLP。
- Logging Exporter——纯调试用的,把 Span 打印到控制台。初学的时候可以用它验证埋点有没有生效。
配置 Exporter 的时候,有一件事特别容易翻车——超时和重试。默认配置可能只有 5 秒超时,如果你后端偶尔波动一下,数据就丢了。我这里给一个生产常用的配置示例:
otlp:
exporter:
endpoint: "http://otel-collector:4317"
tls:
insecure: true
timeout: 15s
retry:
initial_interval: 500ms
max_interval: 30s
max_elapsed_time: 120s
compression: gzip
你看,我习惯把超时拉到 15 秒,加上指数退避重试。这样即使 Collector 短暂不可用,数据也不会一下子全丢了。
3.4 Collector:生产环境的标配
很多人不理解:SDK 直接发到后端不就行了,为什么中间非要加一层 Collector?其实,Collector 是全链路监控中最重要的"阀门"。
它主要由三部分组成:
- Receivers: 接收数据。可以同时接收 OTLP、Jaeger、Prometheus 等多种格式的数据。
- Processors: 处理数据。可以重采样、添加资源属性、过滤掉健康检查等无效 Span。我最常用的是
batch和attributes两个 Processor。 - Exporters: 导出数据到后端存储。可以同时写 Elasticsearch、ClickHouse、Prometheus 等多处。
核心价值: Collector 充当了 SDK 与存储之间的缓冲区。它帮你解耦了数据生产端和数据消费端。你换后端、加采样策略、做数据去重,都只改 Collector 配置就行,业务代码完全不需要动。
举个例子。我们团队曾经接入过监控系统,最开始用的自建 Jaeger,后来团队决定统一迁到 Grafana Tempo。如果没有 Collector,那每个服务都要改 Exporter 配置和重启。但因为我们用了 OTel Collector,把后端出口从 Jaeger 改到 Tempo,只改了一行 Collector 的 Exporter 配置,所有服务都不用动。 这就是 Collector 的价值所在。
3.5 生产落地的小结
我花了两个项目才把 OTel 这套整明白。给你几个可以直抄的结论:
- SDK 选择:用官方 SDK,不要用厂商改版本。优先用自动埋点,业务关键路径用手动埋点补亚迪。
- Exporter:首推 OTLP(gRPC)。配上重试、压缩、合理超时。
- Collector:强烈建议部署,哪怕单实例也行。它是你未来的扩展点。
- 采样策略:生产环境不要全量采样。要么固定采样率,要么基于错误率自适应。
好了,OpenTelemetry 的骨架先讲到这儿。你手头如果有正在跑的应用,可以先试着手动埋一个 Span 看看控制台有没有输出。这个手感很重要。