mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
2597 字
7 分钟
可观测性数据管道
2025-09-14

可观测性数据管道是连接信号产生与信号存储的”血管系统”。它决定了数据如何从应用流向存储后端、如何在流动中被采样/转换/路由、以及如何在后端不可用时保护应用不被反压。

一个设计良好的数据管道可以让你的可观测性系统在数据量增长 10 倍时仍然稳定运行;一个设计糟糕的数据管道则会在流量高峰时成为瓶颈,甚至导致应用不可用。

一、数据管道的定位#

1.1 为什么需要数据管道?#

没有数据管道时,每个应用直接连接存储后端:

graph LR subgraph 问题架构["无管道"] A1["App 1"] --> P["Prometheus"] A2["App 2"] --> T["Tempo"] A3["App 3"] --> L["Loki"] A4["App 4"] --> P A4 --> T A4 --> L end style 问题架构 fill:#ffcdd2,stroke:#c62828

问题:

  • 应用需要配置多个 Exporter,耦合度高
  • 无法统一采样、路由、转换
  • 后端不可用时直接影响应用
  • 无法控制数据量和成本

1.2 有数据管道的架构#

graph TB subgraph 应用层[" 应用层"] A1["App 1"] A2["App 2"] A3["App 3"] end subgraph 管道层[" OTel Collector"] RECV["Receivers"] PROC["Processors"] EXP["Exporters"] end subgraph 存储层[" 存储层"] P["Prometheus"] T["Tempo"] L["Loki"] end A1 -->|"OTLP"| RECV A2 -->|"OTLP"| RECV A3 -->|"OTLP"| RECV RECV --> PROC --> EXP EXP --> P EXP --> T EXP --> L style 应用层 fill:#e8eaf6,stroke:#283593 style 管道层 fill:#e0f2f1,stroke:#00695c style 存储层 fill:#fff3e0,stroke:#e65100

优势:

  • 应用只需配置一个 OTLP Exporter
  • 统一采样、路由、转换
  • 后端不可用时 Collector 缓冲数据
  • 可以在管道层控制数据量和成本

二、OTel Collector 管道架构深入#

2.1 四大组件#

OTel Collector 由四大组件构成:Receiver、Processor、Exporter、Connector。理解每个组件的职责是设计数据管道的基础。

graph LR subgraph Receiver[" Receiver"] R_OTLP["otlp<br/>gRPC + HTTP"] R_PROM["prometheus<br/>Scrape"] R_FILE["filelog<br/>日志文件"] R_KAFKA["kafka<br/>消息队列"] end subgraph Processor[" Processor"] P_ML["memory_limiter"] P_BATCH["batch"] P_FILTER["filter"] P_TRANS["transform"] P_SAMPLE["tail_sampling"] P_K8S["k8sattributes"] end subgraph Exporter[" Exporter"] E_OTLP["otlphttp<br/>→ Tempo"] E_PROM["prometheus<br/>→ VM/Mimir"] E_LOKI["loki<br/>→ Loki"] E_KAFKA["kafka<br/>→ Kafka"] end subgraph Connector[" Connector"] C_SPAN["spanmetrics<br/>Span → 指标"] C_FWD["forward<br/>管道间转发"] end Receiver --> Processor --> Exporter Connector -.->|"跨管道"| Processor style Receiver fill:#e3f2fd,stroke:#1565c0 style Processor fill:#fff3e0,stroke:#e65100 style Exporter fill:#e8f5e9,stroke:#2e7d32 style Connector fill:#f3e5f5,stroke:#6a1b9a

2.2 Receiver 详解#

Receiver 是数据的入口,负责从各种来源接收遥测数据:

Receiver协议适用信号说明
otlpgRPC/HTTP全部OTel 原生协议,最常用
prometheusHTTP Scrape指标兼容 Prometheus 采集
filelog文件日志读取日志文件
kafkaKafka全部从 Kafka 消费数据
zipkinHTTP追踪兼容 Zipkin 格式
jaegergRPC/HTTP追踪兼容 Jaeger 格式
skywalkinggRPC追踪兼容 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: level

2.3 Processor 详解#

Processor 是数据管道的”加工车间”,在 Receiver 和 Exporter 之间对数据进行处理:

Processor功能位置建议说明
memory_limiter内存保护第一个防止 OOM,必须第一个
k8sattributesK8s 元数据注入早期添加 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: 5s

2.4 Exporter 详解#

Exporter 是数据的出口,负责将处理后的数据发送到各种后端:

Exporter协议目标后端说明
otlphttpHTTPTempo/Jaeger/OTel通用 OTLP HTTP 导出
otlpgRPCTempo/Jaeger/OTel通用 OTLP gRPC 导出
prometheusHTTP ScrapeVictoriaMetrics/Mimir暴露 Prometheus 指标端点
lokiHTTPLoki发送日志到 Loki
kafkaKafkaKafka发送到 Kafka 做持久化缓冲
debugConsole开发调试输出到控制台
loggingConsole开发调试详细日志输出
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-traces

2.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: 15s
service:
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 的执行顺序直接影响数据正确性,错误的顺序可能导致数据丢失或性能问题:

graph LR ML["1. memory_limiter<br/>防止 OOM"] --> K8S["2. k8sattributes<br/>注入 K8s 元数据"] K8S --> FILTER["3. filter<br/>过滤不需要的数据"] FILTER --> TRANS["4. transform<br/>转换数据格式"] TRANS --> SAMPLE["5. tail_sampling<br/>采样策略"] SAMPLE --> BATCH["6. batch<br/>批量导出"] style ML fill:#ffcdd2,stroke:#c62828 style K8S fill:#e8f5e9,stroke:#2e7d32 style FILTER fill:#fff3e0,stroke:#e65100 style TRANS fill:#e3f2fd,stroke:#1565c0 style SAMPLE fill:#f3e5f5,stroke:#6a1b9a style BATCH fill:#c8e6c9,stroke:#2e7d32
Warning

memory_limiter 必须是第一个 Processor!如果放在后面,其他 Processor 可能在内存不足时导致 Collector OOM。

三、采样策略详解#

3.1 采样决策点#

graph TB subgraph SDK层[" SDK 层采样"] SDK_HEAD["头部采样<br/>决策: 请求入口"] end subgraph Collector层[" Collector 层采样"] COL_HEAD["头部采样<br/>决策: Collector 接收"] COL_TAIL["尾部采样<br/>决策: 追踪完成"] end SDK_HEAD --> COL_HEAD --> COL_TAIL style SDK层 fill:#e8eaf6,stroke:#283593 style Collector层 fill:#e0f2f1,stroke:#00695c

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: 5

3.4 尾部采样实现原理#

尾部采样的核心挑战是:如何在分布式系统中收集完整的追踪信息,然后做出统一的采样决策?

sequenceDiagram participant SDK1 as SDK (服务A) participant SDK2 as SDK (服务B) participant COL as OTel Collector participant STORE as 存储后端 Note over SDK1: 请求开始<br/>TraceID=abc123 SDK1->>COL: Span A (TraceID=abc123) Note over COL: 缓存 Span A<br/>等待更多 Span SDK1->>SDK2: 调用服务B SDK2->>COL: Span B (TraceID=abc123) Note over COL: 缓存 Span B<br/>追踪完整度增加 SDK2-->>SDK1: 返回结果 SDK1->>COL: Span A' (完成, status=ERROR) Note over COL: decision_wait 超时<br/>评估采样策略 Note over COL: 错误请求 → 保留 COL->>STORE: 导出完整追踪<br/>(Span A + Span B + Span A')

尾部采样的内存开销取决于 num_tracesdecision_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高流量
Warning

尾部采样需要将追踪的所有 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:4318
service:
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"] != nil

4.3 数据路由模式对比#

路由模式实现方式优点缺点
多管道多个 pipelines 配置独立处理、互不影响配置复杂、资源开销大
Filter + 多 Exporter单管道 + 条件过滤配置简单所有数据经过相同 Processor
Connectorspanmetrics 等跨管道桥接仅支持特定场景

五、缓冲与背压#

5.1 Collector 缓冲机制#

graph LR RECV["Receivers"] --> QUEUE["内存队列<br/>可配置大小"] QUEUE --> PROC["Processors"] PROC --> EXP_QUEUE["Exporter 队列"] EXP_QUEUE --> EXP["Exporters"] EXP -->|"背压"| EXP_QUEUE EXP_QUEUE -->|"队列满"| ML["memory_limiter<br/>拒绝新数据"] style RECV fill:#e3f2fd,stroke:#1565c0 style QUEUE fill:#fff3e0,stroke:#e65100 style EXP fill:#e8f5e9,stroke:#2e7d32 style ML fill:#ffcdd2,stroke:#c62828

5.4 持久化缓冲:Kafka#

Note

当后端不可用时,Collector 的发送队列会缓冲数据。但队列大小有限,如果后端长时间不可用,队列会满,新数据会被丢弃。对于关键数据,建议在 Collector 前面加一个持久化缓冲层(如 Kafka)。

receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
exporters:
kafka:
protocol_version: 3.3.1
brokers:
- kafka:9092
topic: otel-traces
receivers:
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每个节点一个 CollectorKubernetes 生产环境资源效率高节点级单点
Gateway集中式 Collector大规模集群 + 多租户集中管理单点瓶颈风险

8.2 多级管道#

graph TB subgraph 第一级["第一级: Agent (DaemonSet)"] AG1["Node 1 Collector<br/>轻量处理"] AG2["Node 2 Collector<br/>轻量处理"] end subgraph 第二级["第二级: Gateway"] GW["Gateway Collector<br/>采样 + 路由 + 转换"] end subgraph 第三级["第三级: 存储"] P["Prometheus"] T["Tempo"] L["Loki"] end AG1 --> GW AG2 --> GW GW --> P GW --> T GW --> L style 第一级 fill:#e3f2fd,stroke:#283593 style 第二级 fill:#e0f2f1,stroke:#00695c style 第三级 fill:#fff3e0,stroke:#e65100

8.3 Agent vs Gateway 配置对比#

processors:
memory_limiter:
limit_mib: 200
batch:
send_batch_size: 1024
timeout: 5s
exporters:
otlphttp:
endpoint: http://otel-gateway:4318
processors:
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 扩展无需额外操作
Warning

使用尾部采样的 Gateway 不能简单地增加副本数——同一个追踪的不同 Span 可能被路由到不同的 Collector 实例,导致采样决策不一致。解决方案是使用一致性哈希负载均衡,确保同一 TraceID 的 Span 始终路由到同一个 Collector 实例。

9.2 一致性哈希配置#

apiVersion: v1
kind: Service
metadata:
name: otel-gateway
spec:
type: ClusterIP
selector:
app: otel-gateway
ports:
- name: otlp-grpc
port: 4317
targetPort: 4317
---
apiVersion: v1
kind: Service
metadata:
name: otel-gateway-headless
spec:
clusterIP: None # headless
selector:
app: otel-gateway
ports:
- name: otlp-grpc
port: 4317
targetPort: 4317

9.3 资源规划#

规模Agent 实例Gateway 实例Gateway CPUGateway 内存
小型(< 50 节点)5012 核4 GiB
中型(50-200 节点)20034 核16 GiB
大型(> 200 节点)500+108 核32 GiB

9.4 生产部署检查清单#

检查项验证方式预期结果
memory_limiter 配置检查配置文件第一个 Processor
发送队列配置检查 Exporter 配置启用 + 合理大小
健康检查curl /healthHTTP 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 两级架构,尾部采样需要一致性哈希,资源规划随规模调整。生产扩展

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

可观测性数据管道
https://blog.souloss.com/posts/observability/observability-data-pipeline/
作者
Souloss
发布于
2025-09-14
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时