3. OTel Collector 架构:Receiver/Processor/Exporter/Pipeline 概念、数据流模型、组件生命周期
OpenTelemetry Collector 是整个可观测性管线的核心执行引擎。理解其四大组件——Receiver、Processor、Exporter 以及将它们串联的 Pipeline——是设计标准模板驱动服务目录的基础。本章将深入剖析这些概念、数据在管线中的流动模型,以及各组件的启动与销毁生命周期。
3.1 核心组件概念与职责
Collector 的架构遵循“接收-处理-导出”的管道模式,每个组件职责单一、可插拔、可复用。
| 组件 | 职责 | 典型实现 | 数据形态 |
|---|---|---|---|
| Receiver | 接收来自不同来源的遥测数据(Trace、Metric、Log),并将其转换为 Collector 内部统一的 pdata 格式。 |
otlp、jaeger、prometheus、kafka、filelog |
gRPC/HTTP 请求、文件流、消息队列 |
| Processor | 对接收到的数据进行过滤、修改、聚合、采样、附加元数据等处理。可以串联多个形成处理链。 | batch、filter、attributes、span、memory_limiter |
内部 pdata 管道 |
| Exporter | 将处理后的数据发送到一个或多个后端系统(如 Jaeger、Prometheus、Datadog、S3)。 | otlp、prometheus、logging、s3、elasticsearch |
gRPC/HTTP 请求、文件写入、消息队列 |
| Pipeline | 定义数据流路径:指定哪些 Receiver 接收数据,经过哪些 Processor 处理,最终由哪些 Exporter 导出。 | YAML 配置中的 pipelines 段 |
逻辑拓扑 |
关键设计原则: Receiver 和 Exporter 通常不直接交互,所有数据必须流经 Pipeline 中定义的 Processor 链。这种设计保证了数据处理逻辑的集中与可审计性。
3.2 数据流模型:从接收到导出的完整路径
数据在 Collector 内部的流动遵循严格的阶段顺序。以下 SVG 图展示了单个 Pipeline 内 Trace 数据的典型流经路径。
3.3 Pipeline 配置与多信号隔离
一个 Collector 实例可以同时运行多个 Pipeline,每个 Pipeline 处理一种信号类型(Traces / Metrics / Logs)。Pipeline 之间完全隔离,数据不会跨 Pipeline 流动。
# 示例:多 Pipeline 配置片段
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
memory_limiter:
check_interval: 1s
limit_mib: 512
exporters:
otlp:
endpoint: "backend.example.com:4317"
tls:
insecure: true
logging:
loglevel: debug
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp, logging]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp]
processors: []
exporters: [logging]
模板设计启示: 在服务目录模板中,Pipeline 的
receivers、processors、exporters 列表应作为可配置参数暴露。不同服务(如高吞吐 Web 服务 vs 批处理任务)可能需要不同的 Processor 组合(如是否启用采样、批处理大小)。
3.4 组件生命周期:启动、运行与关闭
Collector 组件的生命周期由 Collector 框架统一管理,遵循标准的 Start → Run → Shutdown 三阶段模型。理解生命周期对于编写可靠的组件和排查启动故障至关重要。
| 阶段 | 触发条件 | 组件行为 | 典型错误 |
|---|---|---|---|
| 初始化 | Collector 启动,解析配置文件 | 创建组件实例,验证配置参数,建立初始连接(如数据库连接池)。 | 配置缺失、端口冲突、证书无效 |
| 启动 | Collector 调用 Start() |
启动监听端口(Receiver)、启动后台 goroutine(Processor)、建立到后端的连接(Exporter)。 | 端口被占用、后端不可达 |
| 运行 | 正常处理数据 | 持续接收、处理、导出数据。Processor 可能定期执行聚合或刷新操作。 | 内存泄漏、后端限流、数据积压 |
| 关闭 | 收到 SIGTERM/SIGINT 信号 | 停止接收新数据,刷新缓冲区,关闭连接,释放资源。顺序与启动相反。 | 关闭超时、数据丢失(未刷新) |
以下 SVG 图展示了组件生命周期的完整状态机,以及各阶段之间的转换条件。
3.5 组件生命周期中的关键钩子
在编写自定义组件时,开发者需要实现以下接口方法。这些钩子决定了组件在生命周期各阶段的行为。
Start(ctx context.Context, host component.Host) error:启动组件。Receiver 在此处启动 gRPC/HTTP 服务器;Processor 启动后台刷新 goroutine;Exporter 建立到后端的连接。Shutdown(ctx context.Context) error:优雅关闭组件。必须在此方法中完成所有挂起数据的刷新,并释放资源。Collector 会为关闭操作设置超时(默认 30 秒)。Capabilities() consumer.Capabilities(仅 Processor):声明 Processor 是否支持 MutatesData。如果返回true,Collector 会为该 Processor 创建数据副本,避免影响其他 Pipeline 或 Exporter 的数据。
常见陷阱: 如果 Processor 声明
MutatesData: true 但实际上并未修改数据,会导致不必要的内存复制,影响性能。反之,如果修改了数据但声明 false,可能导致后续 Processor 或 Exporter 看到不一致的数据状态。
3.6 数据流模型中的错误处理与背压
Collector 的数据流模型内置了背压(Backpressure)机制,防止后端处理不过来时导致内存溢出。
- Receiver → Processor:Processor 通过
ConsumeTraces/ConsumeMetrics/ConsumeLogs方法返回错误来拒绝数据。Receiver 收到错误后,会向客户端返回 gRPCRESOURCE_EXHAUSTED或 HTTP429 Too Many Requests。 - Processor → Exporter:Exporter 导出失败时,会返回错误。Processor(如
batch)会保留数据并重试,直到成功或达到重试上限。 - 内存限制:
memory_limiterProcessor 会监控内存使用量,当超过阈值时,开始拒绝来自 Receiver 的数据,形成背压。
// 伪代码:背压传递逻辑
func (p *memoryLimiterProcessor) ConsumeTraces(ctx context.Context, td pdata.Traces) error {
if p.memoryUsage > p.limit {
// 拒绝数据,触发背压
return status.Error(codes.ResourceExhausted, "memory limit exceeded")
}
// 正常传递给下一个 Processor
return p.nextConsumer.ConsumeTraces(ctx, td)
}
3.7 本章小结
- Receiver 是数据入口,Processor 是数据处理核心,Exporter 是数据出口,Pipeline 定义它们的连接拓扑。
- 数据流模型遵循严格的阶段顺序,支持背压传递,防止系统过载。
- 组件生命周期分为初始化、启动、运行、关闭四个阶段,关闭顺序与启动顺序相反。
- 在服务目录模板中,Pipeline 的组件列表应作为可配置参数,允许不同服务选择不同的处理链。