用采样控制成本:SDK 与 Collector 配置
决定何时在 SDK 中采样,以及何时在两层 Collector 中使用尾部采样。
保留每一条追踪很快就会变得昂贵,而大多数追踪都是例行请求,没有人会打开它们。采样保留一个有代表性的或有趣的子集。OpenTelemetry 提供两个做决定的地方:追踪开始时在 SDK 中(头部采样),以及追踪完成之后在 Collector 中(尾部采样)。两者都是纯配置。本指南展示每一种,以及如何选择。
SDK 中的头部采样
决定在根 span 创建时做出,所以它很便宜,不需要额外的基础设施。它无法知道请求是否会失败或变慢,因为那还没有发生。
export OTEL_TRACES_SAMPLER=parentbased_traceidratio
export OTEL_TRACES_SAMPLER_ARG=0.1
规范定义的采样器名称包括 always_on、always_off、traceidratio、parentbased_always_on(默认)、parentbased_always_off 和 parentbased_traceidratio。请使用 parentbased_ 变体:它们遵循传入请求的父级的采样决定,所以一条追踪要么整体被保留,要么整体被丢弃,跨越各个服务。在每个服务中使用普通的 traceidratio 会做出相互独立的决定,并产生破碎的追踪。
在声明式配置文件中,同样的想法看起来像这样:
tracer_provider:
sampler:
parent_based:
root:
trace_id_ratio_based:
ratio: 0.1
请查看你的 SDK 文档,了解它在文件格式中支持的采样器名称。
Collector 中的尾部采样
尾部采样会等到追踪完成,然后应用策略。它让你保留每一个错误和每一个慢追踪,外加少量其余的,这是头部采样做不到的。代价是更多的基础设施和内存。
processors:
tail_sampling:
decision_wait: 10s
num_traces: 50000
expected_new_traces_per_sec: 100
policies:
- name: keep-errors
type: status_code
status_code:
status_codes: [ERROR]
- name: keep-slow
type: latency
latency:
threshold_ms: 2000
- name: sample-the-rest
type: probabilistic
probabilistic:
sampling_percentage: 5
工作原理:
decision_wait是该 processor 在看到某条追踪的第一个 span 之后,等待多久再做决定。它必须比你最慢追踪的持续时间更长,否则你会基于不完整的追踪做出决定。num_traces是等待期间在内存中保存多少条追踪。请把它定为大约你的追踪到达速率乘以decision_wait,并留有余量。policies针对每条追踪进行评估。只要任何一条策略说保留,该追踪就会被保留,所以上面的三条策略意味着”保留错误,保留慢的,并且还保留所有追踪中的 5%”。- 其他策略类型包括
string_attribute(匹配某个值,比如客户等级)、numeric_attribute、always_sample、and(组合策略)和composite(在各策略之间分配速率)。
tail_sampling 在 contrib 发行版中,它的选项名称在不断演进,所以请查看你所用版本的 README。
陷阱:一条追踪必须到达同一个 Collector
尾部采样只有在一条追踪的所有 span 都到达同一个 Collector 实例时才有效。在普通负载均衡器后面有多个副本时,同一条追踪的 span 会分散,决定只能基于片段做出。标准的解决方案是两层:
- 第 1 层(负载均衡层) 使用
loadbalancingexporter,按 trace ID 把 span 路由到一个一致的第 2 层实例。 - 第 2 层(采样层) 运行
tail_sampling并导出被保留的追踪。
第 1 层:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
exporters:
loadbalancing:
routing_key: traceID
protocol:
otlp:
tls:
insecure: true
resolver:
dns:
hostname: otel-sampler-headless.observability.svc.cluster.local
port: 4317
service:
pipelines:
traces:
receivers: [otlp]
exporters: [loadbalancing]
第 2 层:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
memory_limiter:
check_interval: 1s
limit_percentage: 80
spike_limit_percentage: 20
tail_sampling:
decision_wait: 10s
policies:
- name: keep-errors
type: status_code
status_code:
status_codes: [ERROR]
- name: sample-the-rest
type: probabilistic
probabilistic:
sampling_percentage: 10
batch:
exporters:
otlp/backend:
endpoint: tempo:4317
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, tail_sampling, batch]
exporters: [otlp/backend]
使用 headless Service,这样 DNS 会列出第 2 层的 Pod,并注意当 Pod 扩容或缩容时,路由会发生变化,少数在途的追踪可能会基于不完整的数据做出决定。让各层保持分离也隔离了故障:采样中的问题不会阻塞摄取。
组合头部与尾部
一种常见且合理的配置:
- SDK 中一个适度的头部采样器(例如 50%),为流量非常大的服务在源头削减体量。
- Collector 中的尾部采样,以保证错误和慢请求得以保留。
请小心:在头部被丢弃的任何东西,都无法在尾部恢复。如果你必须保留所有错误,就不要对这些服务进行激进的头部采样。
如果你先派生指标,指标可以在采样中幸存
丢弃追踪也会丢掉你本可以从中计算出的数字,比如请求速率和延迟百分位。请在采样步骤之前,用 spanmetrics connector 生成指标,这样仪表板就能保持准确:
connectors:
spanmetrics:
service:
pipelines:
traces/all:
receivers: [otlp]
exporters: [spanmetrics, loadbalancing]
metrics/derived:
receivers: [spanmetrics]
processors: [batch]
exporters: [otlphttp/prometheus]
这里每个 span 都馈入 connector,而只有被采样的集合继续进入存储。
选择
| 目标 | 方法 |
|---|---|
| 简单地削减成本,无需新的基础设施 | 使用 parentbased_traceidratio 的头部采样 |
| 保留所有错误和慢请求 | 两层 Collector 中的尾部采样 |
| 保持准确的速率和百分位 | 在采样之前使用 spanmetrics |
| 服务较少,流量较低 | 不采样;等成本变得重要时再重新考虑 |
验证
- 在第 2 层中,使用 Collector 自己的指标(8888 端口)比较进出的 span 数量,确认比例与你的策略匹配。
- 搜索一个已知的失败请求,并确保它的整条追踪都存在。
- 观察第 2 层的内存,因为它会在
decision_wait期间保存追踪。如果它增长,请降低num_traces或增加副本,并让memory_limiter保持在前面。
热门指南
-
OpenTelemetry 详解:SDK、OTLP 与 Collector 在编写任何 YAML 之前,先了解各个活动部件以及配置所在的三个位置。 -
Collector 配置模型:组件、管线与 Provider 了解 Collector YAML 的规则:命名、管线、connector、合并文件和环境变量。 -
使用 OTEL_* 环境变量配置 SDK 使用标准变量为任何语言设置服务名称、exporter、采样和限制。 -
无需修改代码即可为应用插桩:Java、Python 和 Node.js 仅通过环境变量和命令行参数附加 OpenTelemetry agent。 -
让 Collector 达到生产就绪:内存限制、批处理与重试 配置 processor、队列和持久化存储,使遥测数据在过载和故障中存活。 -
使用 Helm 在 Kubernetes 上部署 Collector 安装官方 chart,使用 preset 处理日志和指标,并通过 values 文件覆盖配置。 -
排查 Collector 与 SDK 的问题 当遥测数据没有到达时的系统化检查清单:debug exporter、健康检查、内部指标和常见错误。