为什么需要 Collector
"SDK 直连后端"不是不行,但会有一堆问题:
Collector 把这些痛点统一解决——应用只认 Collector 地址,其他任由运维调配。
管道模型:receiver → processor → exporter
receivers(接收) → processors(加工) → exporters(发出) │ │ │ ├ otlp ├ batch ├ otlp ├ prometheus ├ memory_limiter ├ jaeger ├ jaeger ├ attributes ├ prometheus ├ zipkin ├ resourcedetection ├ datadog ├ kafka ├ tail_sampling ├ loki └ filelog └ transform └ kafka
三种组件各司其职:
Receivers(接收端)
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 prometheus: # 主动去 scrape Prom 指标 config: scrape_configs: - job_name: app static_configs: - targets: [app:8080] jaeger: # 兼容 Jaeger 老格式 protocols: thrift_http: filelog: # 读本地日志文件 include: [/var/log/**/*.log]
OTel 支持 80+ receiver——几乎你见过的任何数据源都能接。
Processors(加工)
processors: batch: # 几乎必装:批量发出提升吞吐 timeout: 10s send_batch_size: 1024 memory_limiter: # 必装:防 OOM check_interval: 1s limit_mib: 512 resourcedetection: # 自动探测 host/k8s/cloud detectors: [env, system, k8s] attributes: # 改 attribute actions: - key: email action: delete - key: env value: prod action: upsert transform: # OTTL 表达式,威力最大 trace_statements: - 'set(attributes["http.status_code"], Int(attributes["status_code"]))' - 'delete_key(attributes, "password")' tail_sampling: # 看完整条 trace 再决定 decision_wait: 30s policies: - name: errors type: status_code status_code: {status_codes: [ERROR]} - name: slow type: latency latency: {threshold_ms: 500} - name: random_10pct type: probabilistic probabilistic: {sampling_percentage: 10}
推荐顺序:
memory_limiter → resourcedetection → 业务处理 → tail_sampling → batchmemory_limiter 放最前,防止后面爆内存;batch 放最后,让送到 exporter 的是打好包的数据。
OTTL:通用转换语言
OTTL(OpenTelemetry Transformation Language)是 transform processor 的配置语言——威力类似 Datadog 的 pipeline 或 Splunk 的 SPL。
transform:
trace_statements:
- 'set(name, "masked") where attributes["user.email"] != nil'
- 'set(attributes["http.route"], Substring(attributes["http.url"], 0, 20))'
- 'keep_keys(attributes, ["http.method", "http.status_code", "user.id"])'
log_statements:
- 'set(severity_text, "ERROR") where severity_number >= 17'
- 'set(body, Concat([body, " [trace=", trace_id.string, "]"], ""))'
学习曲线略陡,但一个团队学会后,所有数据加工都能在 Collector 层完成——应用零改动。
Exporters(发出)
exporters: otlp/datadog: endpoint: ap1.datadoghq.com:443 headers: DD-API-KEY: ${env:DD_API_KEY} otlphttp/honeycomb: endpoint: https://api.honeycomb.io headers: x-honeycomb-team: ${env:HC_KEY} prometheusremotewrite: # 送到 Prom/Mimir endpoint: https://mimir:9009/api/v1/push loki: # 日志给 Loki endpoint: http://loki:3100/loki/api/v1/push kafka: # 异步走 Kafka 再消费 brokers: [kafka:9092] topic: otel-traces file: # 落盘调试 path: /tmp/otel.json debug: # 控制台打印,调试利器 verbosity: detailed
OTel Collector 支持 100+ exporter,包括主流 APM/日志/Metric 后端,以及存储层(Kafka、S3、ClickHouse)。
Pipeline 组装
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, resourcedetection, tail_sampling, batch]
exporters: [otlp/datadog, otlphttp/honeycomb] # 同时发俩
metrics:
receivers: [otlp, prometheus]
processors: [memory_limiter, batch]
exporters: [prometheusremotewrite]
logs:
receivers: [otlp, filelog]
processors: [memory_limiter, transform, batch]
exporters: [loki]
extensions: [health_check, pprof, zpages]
telemetry:
logs:
level: info
metrics:
address: 0.0.0.0:8888
Pipeline 是"3D"交叉:三种信号 × 三种组件,任意拼接。一个 Collector 实例可以同时跑 traces/metrics/logs 三条 pipeline。
部署模式:Agent vs Gateway
| Agent(边车) | Gateway(集群) | |
|---|---|---|
| 位置 | 每个主机 / 每个 K8s 节点 DaemonSet | 独立 Deployment,有多副本 |
| 职责 | 就近接收、基础加工、转发 | 集中策略、tail sampling、后端路由 |
| 规模 | 随节点数自动扩 | 独立水平扩容 |
| 延迟 | 低(同节点) | 多一跳 |
应用 → Agent(节点上) → Gateway(集群) → 后端
localhost 同 k8s 多后端
生产推荐:Agent + Gateway 两层——Agent 低延迟就近接,Gateway 做 tail sampling 和多后端扇出。
Tail-based Sampling 深入
头部采样(SDK 层)的缺陷:请求开始时你不知道它会不会出错。决定采 10%,9 条慢请求里可能只留下 1 条。
Tail-based Sampling(Collector 层)在整条 trace 聚齐后再决策:
- 出错的 trace:100% 保留
- 延迟超过 500ms 的:100% 保留
- 其他:保留 1%
processors:
tail_sampling:
decision_wait: 30s # 等 30s 凑齐整条 trace
num_traces: 100000 # 最多缓存的 trace 数
policies:
- name: keep_errors
type: status_code
status_code: {status_codes: [ERROR]}
- name: keep_slow
type: latency
latency: {threshold_ms: 500}
- name: keep_vip_tenant
type: string_attribute
string_attribute:
key: tenant.id
values: [vip-customer-1, vip-customer-2]
- name: baseline
type: probabilistic
probabilistic: {sampling_percentage: 1}
Tail sampling 要求一条 trace 的所有 span 都到同一个 Collector 实例——否则决策时看不到全貌。多副本 Gateway 需要用
loadbalancing exporter 按 trace_id 哈希分发。
负载均衡(loadbalancing exporter)
Agent → Gateway LB → {Gateway A, Gateway B, Gateway C} → tail sampling 各自决策
按 trace_id 哈希:同一条 trace 永远去同一台
exporters:
loadbalancing:
routing_key: traceID
protocol:
otlp:
tls: {insecure: true}
resolver:
k8s:
service: otel-gateway.observability
ports: [4317]
运维可观测性:Collector 自己的 metrics
Collector 自己也有 metrics——要不它挂了你咋知道?
otelcol_receiver_accepted_spans—— 接到了多少 spanotelcol_exporter_sent_spans—— 发出去了多少otelcol_exporter_send_failed_spans—— 发失败了多少 ⚠️otelcol_processor_dropped_spans—— processor 丢了多少
这些 metrics 自己也用 telemetry.metrics.address 暴露出来,你的 Prometheus 可以 scrape——把 Collector 纳入自己的监控体系。
配置热加载
改了配置?不想重启?
# 发 SIGHUP 触发 reload kill -HUP $(pgrep otelcol) # 或者用 config_sources 拉远程配置 + file watch
热加载不是所有组件都支持,但 receivers/exporters/processors 大多数都行。生产上建议滚动重启更稳妥。
OTel Collector vs Fluent Bit
| OTel Collector | Fluent Bit | |
|---|---|---|
| 起家 | 可观测性全栈 | 日志专家 |
| 覆盖 | trace/metric/log 三合一 | 日志 + metric(弱) |
| 生态 | OTel 生态核心 | K8s 集群日志首选 |
| 体积 | ~30MB | ~500KB |
| 场景 | 可观测性统一管道 | 轻量日志 forwarder |
不互斥:很多团队用 Fluent Bit 做 K8s 日志采集 → 送到 OTel Collector 统一加工 → 送多后端。
本章小结
- Collector = receiver + processor + exporter 的可组合管道
- 处理三种信号(trace/metric/log),每种走自己的 pipeline
- 部署两层:Agent(节点) + Gateway(集群)
- Tail-based sampling 让你"保留所有错/慢 trace + 采样正常流量"
- OTTL 让数据加工(脱敏、重命名、提取)在运维层完成
- Collector 自己的 metrics 要被 Prom 监控——别让观测系统成盲点