可观测性数据管道是连接信号产生与信号存储的”血管系统”。它决定了数据如何从应用流向存储后端、如何在流动中被采样/转换/路由、以及如何在后端不可用时保护应用不被反压。
一个设计良好的数据管道可以让你的可观测性系统在数据量增长 10 倍时仍然稳定运行;一个设计糟糕的数据管道则会在流量高峰时成为瓶颈,甚至导致应用不可用。
一、数据管道的定位
1.1 为什么需要数据管道?
没有数据管道时,每个应用直接连接存储后端:
问题:
- 应用需要配置多个 Exporter,耦合度高
- 无法统一采样、路由、转换
- 后端不可用时直接影响应用
- 无法控制数据量和成本
1.2 有数据管道的架构
优势:
- 应用只需配置一个 OTLP Exporter
- 统一采样、路由、转换
- 后端不可用时 Collector 缓冲数据
- 可以在管道层控制数据量和成本
二、OTel Collector 管道架构深入
2.1 四大组件
OTel Collector 由四大组件构成:Receiver、Processor、Exporter、Connector。理解每个组件的职责是设计数据管道的基础。
2.2 Receiver 详解
Receiver 是数据的入口,负责从各种来源接收遥测数据:
| Receiver | 协议 | 适用信号 | 说明 |
|---|---|---|---|
otlp | gRPC/HTTP | 全部 | OTel 原生协议,最常用 |
prometheus | HTTP Scrape | 指标 | 兼容 Prometheus 采集 |
filelog | 文件 | 日志 | 读取日志文件 |
kafka | Kafka | 全部 | 从 Kafka 消费数据 |
zipkin | HTTP | 追踪 | 兼容 Zipkin 格式 |
jaeger | gRPC/HTTP | 追踪 | 兼容 Jaeger 格式 |
skywalking | gRPC | 追踪 | 兼容 SkyWalking 格式 |
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 max_recv_msg_size_mib: 4 http: endpoint: 0.0.0.0:4318 maxRequestBodySize: 4194304 prometheus: config: scrape_configs: - job_name: 'otel-collector' scrape_interval: 15s static_configs: - targets: ['localhost:8888'] filelog: include: [/var/log/app/*.log] parsers: json: time_key: timestamp severity_key: level2.3 Processor 详解
Processor 是数据管道的”加工车间”,在 Receiver 和 Exporter 之间对数据进行处理:
| Processor | 功能 | 位置建议 | 说明 |
|---|---|---|---|
memory_limiter | 内存保护 | 第一个 | 防止 OOM,必须第一个 |
k8sattributes | K8s 元数据注入 | 早期 | 添加 Pod/Service 信息 |
filter | 数据过滤 | 中间 | 按条件过滤不需要的数据 |
transform | 数据转换 | 中间 | 修改属性、重命名指标 |
tail_sampling | 尾部采样 | 中间 | 基于完整追踪信息采样 |
probabilistic_sampler | 概率采样 | 中间 | 按概率采样 |
batch | 批量处理 | 最后一个 | 减少网络请求次数 |
processors: memory_limiter: check_interval: 5s limit_mib: 400 spike_limit_mib: 100 k8sattributes: auth_type: serviceAccount passthrough: false filter: node_from_env_var: KUBE_NODE_NAME extract: metadata: - k8s.pod.name - k8s.namespace.name - k8s.deployment.name filter: error_mode: ignore traces: span: - 'attributes["http.route"] == "/healthz"' - 'attributes["http.route"] == "/readyz"' transform: error_mode: ignore trace_statements: - context: span statements: - set(attributes["service.name"], attributes["service"]) where attributes["service"] != nil - delete_key(attributes, "user_id") - set(attributes["env"], "production") batch: send_batch_size: 1024 send_batch_max_size: 2048 timeout: 5s2.4 Exporter 详解
Exporter 是数据的出口,负责将处理后的数据发送到各种后端:
| Exporter | 协议 | 目标后端 | 说明 |
|---|---|---|---|
otlphttp | HTTP | Tempo/Jaeger/OTel | 通用 OTLP HTTP 导出 |
otlp | gRPC | Tempo/Jaeger/OTel | 通用 OTLP gRPC 导出 |
prometheus | HTTP Scrape | VictoriaMetrics/Mimir | 暴露 Prometheus 指标端点 |
loki | HTTP | Loki | 发送日志到 Loki |
kafka | Kafka | Kafka | 发送到 Kafka 做持久化缓冲 |
debug | Console | 开发调试 | 输出到控制台 |
logging | Console | 开发调试 | 详细日志输出 |
exporters: otlphttp/tempo: endpoint: http://tempo:4318 sending_queue: enabled: true num_consumers: 10 queue_size: 5000 retry_on_failure: enabled: true initial_interval: 5s max_interval: 30s max_elapsed_time: 300s prometheus: endpoint: 0.0.0.0:8889 namespace: otel loki: endpoint: http://loki:3100/loki/api/v1/push default_labels_enabled: exporter: false kafka: protocol_version: 3.3.1 brokers: - kafka:9092 topic: otel-traces2.5 Connector 详解
Connector 是 OTel Collector 的”跨管道桥梁”,允许一个管道的输出成为另一个管道的输入:
connectors: spanmetrics: histogram: explicit: buckets: [2ms, 4ms, 6ms, 8ms, 10ms, 50ms, 100ms, 200ms, 400ms, 800ms, 1s, 5s] dimensions: - name: http.method - name: http.status_code - name: http.route metrics_flush_interval: 15sservice: pipelines: traces: receivers: [otlp] processors: [memory_limiter, batch] exporters: [otlphttp/tempo, spanmetrics] # spanmetrics 是 connector metrics: receivers: [otlp, spanmetrics] # spanmetrics 的输出作为 metrics 的输入 processors: [memory_limiter, batch] exporters: [prometheus]| Connector | 功能 | 输入 | 输出 |
|---|---|---|---|
spanmetrics | 从 Span 生成指标 | 追踪 | 指标 |
forward | 管道间转发 | 任意 | 任意 |
count | 计数连接器 | 任意 | 指标 |
2.6 管道配置
service: pipelines: traces: receivers: [otlp] processors: [memory_limiter, k8sattributes, tail_sampling, batch] exporters: [otlphttp/tempo, otlphttp/debug] metrics: receivers: [otlp] processors: [memory_limiter, k8sattributes, filter, transform, batch] exporters: [prometheus, otlphttp/debug] logs: receivers: [otlp] processors: [memory_limiter, k8sattributes, filter/logs, batch] exporters: [loki, otlphttp/debug]2.7 Processor 执行顺序
Processor 的执行顺序直接影响数据正确性,错误的顺序可能导致数据丢失或性能问题:
memory_limiter 必须是第一个 Processor!如果放在后面,其他 Processor 可能在内存不足时导致 Collector OOM。
三、采样策略详解
3.1 采样决策点
3.2 头部采样(Head-based Sampling)
头部采样在请求入口处做出采样决策,所有后续 Span 都遵循相同的决策:
| 优点 | 缺点 |
|---|---|
| 零延迟——不需要等待追踪完成 | 无法基于追踪结果做决策 |
| 实现简单 | 可能错过所有错误请求 |
| 内存开销极低 | 无法保证错误请求被采集 |
3.3 尾部采样(Tail-based Sampling)
尾部采样等待整个追踪完成后,根据追踪结果做出采样决策。这是生产环境推荐的采样策略:
processors: tail_sampling: decision_wait: 10s # 等待 10s 收集完整追踪 num_traces: 100000 # 内存中缓存的追踪数 expected_new_traces_per_sec: 1000 policies: - name: error-policy type: status_code status_code: status_codes: - ERROR - UNSET - name: slow-policy type: latency latency: threshold_ms: 1000 - name: critical-service-policy type: string_attribute string_attribute: key: service.name values: - payment-service - auth-service - name: fallback-policy type: probabilistic probabilistic: sampling_percentage: 53.4 尾部采样实现原理
尾部采样的核心挑战是:如何在分布式系统中收集完整的追踪信息,然后做出统一的采样决策?
尾部采样的内存开销取决于 num_traces 和 decision_wait:
| 配置 | 内存开销 | 适用场景 |
|---|---|---|
num_traces=10000, decision_wait=5s | ~200 MiB | 低流量 |
num_traces=100000, decision_wait=10s | ~2 GiB | 中流量 |
num_traces=1000000, decision_wait=30s | ~20 GiB | 高流量 |
尾部采样需要将追踪的所有 Span 缓存在内存中,内存开销与流量成正比。在高流量场景下,务必配置足够的内存,否则 Collector 会 OOM。
3.5 概率采样(Probabilistic Sampling)
概率采样是最简单的采样策略,按固定比例保留数据:
3.6 采样策略对比
| 策略 | 保留率 | 延迟 | 内存开销 | 适用场景 |
|---|---|---|---|---|
| 全量采集 | 100% | 无 | 无 | 低流量服务 |
| 概率采样 10% | 10% | 无 | 无 | 高流量低错误率 |
| 头部采样 | 可配置 | 无 | 极低 | 简单场景 |
| 尾部采样(错误+慢) | ~5-20% | 10s | 高 | 生产环境推荐 |
| 自适应采样 | 动态 | 动态 | 中 | 大规模生产 |
四、路由与转换
4.1 条件路由
processors: filter/critical: error_mode: ignore traces: span: - 'attributes["service.name"] == "payment-service"' filter/non-critical: error_mode: ignore traces: span: - 'attributes["service.name"] != "payment-service"'exporters: otlphttp/critical: endpoint: http://tempo-critical:4318 otlphttp/standard: endpoint: http://tempo-standard:4318service: pipelines: traces/critical: receivers: [otlp] processors: [memory_limiter, filter/critical, batch] exporters: [otlphttp/critical] traces/standard: receivers: [otlp] processors: [memory_limiter, filter/non-critical, tail_sampling, batch] exporters: [otlphttp/standard]4.2 数据转换
processors: transform: error_mode: ignore trace_statements: - context: span statements: - set(attributes["service.name"], attributes["service"]) where attributes["service"] != nil - delete_key(attributes, "user_id") - delete_key(attributes, "request_id") - set(attributes["env"], "production") metric_statements: - context: datapoint statements: - set(attributes["service"], attributes["service.name"]) where attributes["service.name"] != nil4.3 数据路由模式对比
| 路由模式 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| 多管道 | 多个 pipelines 配置 | 独立处理、互不影响 | 配置复杂、资源开销大 |
| Filter + 多 Exporter | 单管道 + 条件过滤 | 配置简单 | 所有数据经过相同 Processor |
| Connector | spanmetrics 等 | 跨管道桥接 | 仅支持特定场景 |
五、缓冲与背压
5.1 Collector 缓冲机制
5.4 持久化缓冲:Kafka
当后端不可用时,Collector 的发送队列会缓冲数据。但队列大小有限,如果后端长时间不可用,队列会满,新数据会被丢弃。对于关键数据,建议在 Collector 前面加一个持久化缓冲层(如 Kafka)。
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317exporters: kafka: protocol_version: 3.3.1 brokers: - kafka:9092 topic: otel-tracesreceivers: kafka: brokers: - kafka:9092 topics: - otel-traces consumer_group: otel-collector-gateway| 缓冲方式 | 持久性 | 延迟 | 复杂度 | 适用场景 |
|---|---|---|---|---|
| 内存队列 | 无(进程重启丢失) | 低 | 低 | 短暂后端不可用 |
| 磁盘 WAL | 有 | 中 | 中 | 中等后端不可用 |
| Kafka | 有(多副本) | 中 | 高 | 长时间后端不可用、关键数据 |
六、多管道配置
6.1 多管道设计原则
多管道允许不同的信号走不同的处理路径,是数据管道灵活性的核心:
service: pipelines: traces/critical: receivers: [otlp] processors: [memory_limiter, filter/critical, batch] exporters: [otlphttp/tempo-critical] traces/standard: receivers: [otlp] processors: [memory_limiter, filter/non-critical, tail_sampling, batch] exporters: [otlphttp/tempo-standard] metrics: receivers: [otlp, spanmetrics] processors: [memory_limiter, filter/metrics, transform, batch] exporters: [prometheus] logs: receivers: [otlp] processors: [memory_limiter, filter/logs, batch] exporters: [loki]6.2 多管道资源隔离
service: pipelines: traces: processors: [memory_limiter/traces, batch/traces] metrics: processors: [memory_limiter/metrics, batch/metrics] logs: processors: [memory_limiter/logs, batch/logs]processors: memory_limiter/traces: check_interval: 5s limit_mib: 800 memory_limiter/metrics: check_interval: 5s limit_mib: 200 memory_limiter/logs: check_interval: 5s limit_mib: 400 batch/traces: send_batch_size: 2048 timeout: 5s batch/metrics: send_batch_size: 1024 timeout: 10s batch/logs: send_batch_size: 4096 timeout: 3s七、管道的可观测性
7.1 Collector 自身指标
OTel Collector 暴露了自身的运行指标,用于监控管道健康:
7.2 关键告警规则
groups: - name: otel-collector rules: - alert: CollectorHighRefusalRate expr: rate(otelcol_receiver_refused_spans[5m]) > 100 for: 5m labels: severity: warning annotations: summary: "OTel Collector 拒绝率过高" description: "Collector {{ $labels.instance }} 拒绝率 {{ $value }} spans/s" - alert: CollectorQueueBacklog expr: otelcol_exporter_queue_size > 4000 for: 5m labels: severity: warning annotations: summary: "OTel Collector 导出队列积压" description: "队列 {{ $labels.exporter }} 积压 {{ $value }} 条"八、数据管道设计模式
8.1 三种部署模式
| 模式 | 架构 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| Sidecar | 每个 Pod 一个 Collector | 安全隔离要求高 | 隔离性好 | 资源开销大 |
| DaemonSet | 每个节点一个 Collector | Kubernetes 生产环境 | 资源效率高 | 节点级单点 |
| Gateway | 集中式 Collector | 大规模集群 + 多租户 | 集中管理 | 单点瓶颈风险 |
8.2 多级管道
8.3 Agent vs Gateway 配置对比
processors: memory_limiter: limit_mib: 200 batch: send_batch_size: 1024 timeout: 5sexporters: otlphttp: endpoint: http://otel-gateway:4318processors: memory_limiter: limit_mib: 2000 k8sattributes: auth_type: serviceAccount tail_sampling: decision_wait: 10s num_traces: 100000 policies: [...] transform: error_mode: ignore trace_statements: [...] batch: send_batch_size: 2048 timeout: 5s九、生产扩展考量
9.1 水平扩展
OTel Collector 的水平扩展策略取决于部署模式:
| 部署模式 | 扩展方式 | 注意事项 |
|---|---|---|
| DaemonSet | 自动随节点扩展 | 无需额外操作 |
| Gateway | 增加副本数 + 负载均衡 | 尾部采样需要一致性哈希 |
| Sidecar | 随 Pod 扩展 | 无需额外操作 |
使用尾部采样的 Gateway 不能简单地增加副本数——同一个追踪的不同 Span 可能被路由到不同的 Collector 实例,导致采样决策不一致。解决方案是使用一致性哈希负载均衡,确保同一 TraceID 的 Span 始终路由到同一个 Collector 实例。
9.2 一致性哈希配置
apiVersion: v1kind: Servicemetadata: name: otel-gatewayspec: type: ClusterIP selector: app: otel-gateway ports: - name: otlp-grpc port: 4317 targetPort: 4317---apiVersion: v1kind: Servicemetadata: name: otel-gateway-headlessspec: clusterIP: None # headless selector: app: otel-gateway ports: - name: otlp-grpc port: 4317 targetPort: 43179.3 资源规划
| 规模 | Agent 实例 | Gateway 实例 | Gateway CPU | Gateway 内存 |
|---|---|---|---|---|
| 小型(< 50 节点) | 50 | 1 | 2 核 | 4 GiB |
| 中型(50-200 节点) | 200 | 3 | 4 核 | 16 GiB |
| 大型(> 200 节点) | 500+ | 10 | 8 核 | 32 GiB |
9.4 生产部署检查清单
| 检查项 | 验证方式 | 预期结果 |
|---|---|---|
| memory_limiter 配置 | 检查配置文件 | 第一个 Processor |
| 发送队列配置 | 检查 Exporter 配置 | 启用 + 合理大小 |
| 健康检查 | curl /health | HTTP 200 |
| 指标暴露 | Prometheus 查询 | 能看到 Collector 指标 |
| 背压处理 | 关闭后端后发送数据 | Collector 缓冲而非崩溃 |
| 采样策略 | 对比发送量和存储量 | 符合采样率 |
| 多管道独立 | Collector 日志 | 无错误 |
十、动手实践
10.3 验证清单
| 检查项 | 验证方式 | 预期结果 |
|---|---|---|
| 三管道独立运行 | Collector 日志 | 无错误 |
| 采样策略生效 | 对比发送量和存储量 | 符合采样率 |
| 背压处理 | 关闭后端后发送数据 | Collector 缓冲 |
| Collector 指标 | Prometheus 查询 | 能看到运行指标 |
十一、本章小结
上一章深入解读了eBPF 零仪器化可观测性的内部机制。 这一章覆盖了可观测性数据管道的关键设计。
| 主题 | 核心要点 | 关键词 |
|---|---|---|
| 管道定位 | 连接信号产生与存储的”血管系统”,解耦应用与后端。 | 管道定位 |
| 四大组件 | Receiver(入口)、Processor(处理)、Exporter(出口)、Connector(跨管道桥接)。 | 四大组件 |
| Processor 顺序 | memory_limiter 必须第一个,batch 最后一个。 | Processor 顺序 |
| 采样策略 | 头部采样简单但粗糙,尾部采样精确但开销大,概率采样适合简单场景。 | 采样策略 |
| 尾部采样 | 生产环境推荐方案,保留错误和慢请求,需要关注内存开销。 | 尾部采样 |
| 路由与转换 | 按条件路由到不同后端,Transform Processor 修改数据格式。 | 路由与转换 |
| 缓冲与背压 | 发送队列缓冲后端不可用时的数据,memory_limiter 防止 OOM,Kafka 提供持久化缓冲。 | 缓冲与背压 |
| 多管道 | 不同信号走不同处理路径,关键服务全量采集,普通服务尾部采样。 | 多管道 |
| 生产扩展 | DaemonSet + Gateway 两级架构,尾部采样需要一致性哈希,资源规划随规模调整。 | 生产扩展 |
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
部分信息可能已经过时






