OTLP 是什么及其幕后工作原理
如果你在过去十年里用过可观测性工具,大概率被碎片化的工具和库折腾过。每种遥测信号都需要一套专门的工具,数据格式互不兼容,彼此之间几乎没有关联。比如日志无法关联到 trace,你只能靠猜哪些 trace 对应哪些事件。
OpenTelemetry 协议(OTLP)通过将遥测数据的生成方式与分析位置解耦来解决这个问题。OTLP 是一种通用的、厂商中立的数据格式,用于在任何兼容的源和目的地之间传输遥测数据(主要是 logs、metrics 和 traces)。它由 OpenTelemetry(OTel)项目定义,充当客户端(应用)和服务器(OTel Collector,或 SigNoz 这类原生支持 OpenTelemetry 的可观测性后端)之间的通用语言。配置完成后,你的应用只需输出统一的数据流,任何兼容的后端都能直接接收,无需额外处理。
为什么需要 OTLP?
在 OTLP 出现之前,可观测性领域非常碎片化,因为不同的信号需要完全不同的工具。由于缺乏统一标准,数据格式在整个技术栈中互不兼容,关键的上下文信息就这样丢失了。
此外,工程师还常常被厂商锁定。因为应用代码使用的是特定厂商的埋点 agent,更换服务商往往要花费数周时间。当时的主流心态就是让现有工具凑合能用,而不是想着去改进。
日常使用这些工具的体验同样令人抓狂。遥测数据被发送到各自隔离的、按信号划分的平台——一个管 tracing,另一个管日志,等等——排查一个故障就需要不停地切换上下文。任何排查过高压力生产问题的人都知道,追踪各种变动有多难。想象一下,在因果关系几乎无从得知的情况下还要这么做!
OTLP 的统一标准让团队能够用单一后端满足所有可观测性需求。移除了供应商锁定壁垒后,可观测性工具不得不在功能层面展开竞争,而非在数据格式兼容性上。由于所有兼容 OTLP 的后端接收到的都是相同标准化数据,团队可以跨全栈关联追踪、指标和日志——这种整体视角在以往碎片化的工具栈中几乎是不可能实现的。

OTLP 幕后工作机制
在可观测性领域,数据至关重要,数据丢失或格式错误均不容忍。哪怕仅仅 500 毫秒的数据丢失,都可能让工程师难以理解和修复复杂分布式系统中的问题。OpenTelemetry 围绕四项原则设计了 OTLP 格式,以确保数据可靠性:
- 层级化数据组织,消除跨批次的数据冗余
- 高效编码,利用 Protobuf 实现紧凑且模式安全的负载
- 可靠传输,通过严格的请求-响应模型保证
- 内置背压,从容应对服务器过载情况

OTLP 数据层级:资源 → 范围 → 数据
每个 OTLP 负载都遵循三层结构,将遥测数据包裹在使其有意义所需的上下文之中:
- Resource:Resource 位于批次数据的根部,用于定义产生遥测数据的实体(例如
service.name = payments)。它在一个批次中只定义一次,所有数据点会自动继承该信息。 - Scope:Instrumentation scope 嵌套在 Resource 内部,用于标识生成数据的具体代码或库(例如
telemetry.sdk.version = 1.38.1)。 - Data:Scope 内部包含实际负载:由插桩应用生成的
Spans、LogRecords或MetricPoints列表。
这种结构确保每个数据点不仅包含测量值,还携带其来源和生成方式,而无需在每条记录中重复这些上下文信息。
Protobuf:速度与稳定性
Protobuf 是 Google 推出的独立于平台和语言的数据序列化格式,常用于服务间传输结构化数据。
Protobuf 将消息编码为紧凑的二进制格式,从而减小负载体积并提升数据传输速度。它还强制实施严格的 schema 兼容性规则,确保随着消息定义随时间演进,服务仍能保持兼容性。
OTLP 利用这些特性传输紧凑的二进制消息,其序列化、传输和解析速度显著快于 JSON 等文本格式。
由于 Protobuf 能优雅地处理 schema 演进,OTel 库可以独立迭代,OTLP 的小版本变更不会强制下游依赖更新。
JSON 兼容性虽然 Protobuf 是首选(也是默认)的消息 schema,OTLP 也支持通过 HTTP 传输的 JSON 编码消息。这在 Web 环境中特别有用——加载完整的 Protobuf 库可能会让 JavaScript 包体积暴涨。此外,JSON 也常用于兼容现有的基于 JSON 的数据接入方案,或便于调试(因为 JSON 人类可读)。
基于请求-响应模型的可靠投递
如果“数据是神圣的”,那“发完就不管”就行不通了。
OTLP 采用严格的请求-响应模型:客户端发出请求后,服务器必须显式地解析、入队并确认,这次事务才算完成。一旦传输失败,客户端会重试请求,避免间歇性的数据丢失。
关键在于,OTLP 的可靠性保证每次只覆盖一对节点之间的一跳,比如被埋点的应用和 OTLP 兼容的后端(可以是 OTel Collector 实例,也可以是可观测性后端本身)。
要在整条可观测性管道上实现端到端的可靠性,OTLP 会把这些确认跳串联起来,在整条管道中形成一条连续的投递路径。
OTLP 服务器可以返回三种响应类型,每种都会影响客户端的下一步动作:
- 完全成功:服务器验证并接受了整个请求负载,客户端可以发送下一批数据。
- 部分成功:这是 OTLP 的一项关键特性——服务器会接收有效数据,但只拒绝其中格式有问题的具体条目。响应中会包含失败详情,让客户端清楚知道哪里出了问题。由于这类拒绝是由确定性问题(如格式无效)导致的,客户端不会重试这类请求,从而节省 CPU 和网络资源。
- 失败:表示服务器无法处理数据。对于网络超时等瞬时错误,客户端会重试请求;对于数据验证失败等永久性错误,客户端会丢弃数据,以避免格式错误的请求阻塞管道。

智能批处理
众所周知,网络调用成本高昂,如果每个请求只发送单个数据点,任何数据传输管道都会很快遇到瓶颈。OTLP 通过将遥测数据分组为批次来减少这种开销。
上述描述的“资源 → 范围 → 数据”层级结构在此处起着关键作用。在较旧的系统中,元数据通常是“扁平”的,即每个数据点都携带自己的副本。如果你从结账服务发送了 100 条日志条目,每一条都会重复 service.name = checkout 字符串,从而浪费带宽和存储空间。由于 OTLP 在资源(Resource)和范围(Scope)层级定义元数据,它只需每个批次写入一次,下方的所有数据点都会继承这些元数据。
内置背压与流控
高吞吐量的 OTLP 客户端很容易让消费其数据的服务器不堪重负。为了处理这种情况,OTLP 将背压(backpressure)信号直接集成到协议中,使过载的服务器能够告知客户端减速,而不是默默地丢弃数据或崩溃。
在实际操作中,过载的服务器会返回特定的状态码——HTTP 429 Too Many Requests 或 gRPC RESOURCE_EXHAUSTED——并附带 Retry-After 头(HTTP)或元数据(gRPC),明确告知客户端等待的确切时长。这防止了“惊群效应”,即客户端在无延迟的情况下重试失败的请求,从而完全压垮接收服务器。

OTLP 还支持 gzip 压缩,允许客户端在增加少量 CPU 压缩和解压开销的前提下,大幅缩减传输载荷的体积。
传输协议:gRPC 和 HTTP
OTLP 支持通过两种协议传输数据:gRPC 和 HTTP。这两种传输方式均采用相同的 Protobuf 共享模式,用以保护你的遥测数据