LabHub
学习 学习路径 课程

OTCA — OpenTelemetry 认证助理

尾部采样不是免费的 — 三笔成本

在 LabHub 中继续学习

一句话总结

头部采样在一切尚未发生时就作决定,因此会按照稀有事件本身的稀有程度,精准地将其丢弃。尾部采样根据结果决定,却要付出三种成本:不会减少网络流量、消耗大量内存,并要求基于 trace ID 路由。头部已经丢弃的内容,尾部无法复原。

概念图: 按照稀有事件本身的稀有程度,精准地将其丢弃 · 丢弃什么 · 排除 · 不降低

为什么需要它

对多数组织而言,全量存储成本不可接受。问题在于丢弃什么。假设使用 1% 头部采样,调查每小时 5 个错误。

보존되는 오류 트레이스 = 5 × 0.01 = 시간당 0.05건
1건을 보려면 평균 20시간 대기

这就是头部采样的实际结局:需要调查时,那条 trace 并不存在;剩下的又全是正常请求,没有查看价值。

工作原理

尾部采样在 trace 完成前将 span 缓存在内存,看到结果后再决定。存在错误就保留,速度慢就保留,其余只保留少量。每条策略都是“保留条件”,多条策略中任一匹配就会保留。因此,要排除健康检查,应使用反转匹配的 invert_match

项目 头部采样 尾部采样
决策时刻 创建 root span 时 经过 decision_wait
保留错误、慢请求 只按概率 通过规则 100% 保留
agent、网络成本 按比例降低 不降低
后端存储成本 降低 降低
Collector 内存 可忽略 按每秒 trace 数 × 等待时间缓存
运维要求 必须基于 trace ID 路由

成本 1——网络不会减少。 要做决定,所有 span 必须先到达 Collector,因此节省的只有后端存储和索引。Collector 自身 CPU 与网络消耗反而增加。

成本 2——内存。 decision_wait 期间必须保留全部 span,计算式很简单。

초당 트레이스 수 × decision_wait(초) × 트레이스당 스팬 수 × 스팬 크기 = 버퍼 메모리

예: 10,000 trace/s × 30s × 12 스팬 × 1.2KB
  = 4,320,000 KB = 약 4,219 MB (여유 2배면 약 8,438 MB)

num_traces 是同时驻留内存的 trace 数上限,超限时最旧的 trace 会被强制决定。所需值也来自同一乘法:每秒 trace 数 × decision_wait。10,000 trace/s、等待 30 秒,需要 300,000。

成本 3——路由。 同一 trace 的所有 span 必须到达同一个 Collector 实例。横向扩容后若在前面放普通负载均衡器,一个 trace 的 span 会散到多个实例,各实例只看碎片便作决定,结果就是随机断裂的 trace。解决办法是在前层部署使用 routing_key: traceID 的 loadbalancing exporter。

同理,DaemonSet 中不能进行尾部采样。 每节点一个 Collector 时,一条 trace 的 span 会分散到不同节点,各 agent 只能看到一部分。尾部采样只能放在 Deployment(gateway)层。

现场会遇到的情况

代价最高的一次事故,是流量增长后仍把 num_traces 设为 50,000。峰值为 10,000 trace/s,decision_wait 为 30 秒,需要 300,000;上限只有六分之一,旧 trace 持续被强制决定。叠加内存压力后 Collector 反复 OOM 重启,丢失 5 分钟数据。指标几乎没有异常——数据仍在“正常”发送,只是后端缺少特定 trace。

教训有两条。第一,启用 tail_sampling 前先做乘法。第二,数据消失而指标安静时,暂时从 pipeline 移除 tail_sampling 再复现,这是最快区分方法。

实际组合通常是:超高流量服务先在头部降到 10~50%,再在其上使用尾部采样捞出错误和慢请求。头部已丢弃的内容尾部无法恢复,因此头部比例原则上应在可承受范围内尽量高。

下一实验要做什么

/root/otca-sampling/ 下编写五条尾部采样策略:100% 保留错误和延迟的结果策略;用 invert_match 排除健康检查;用 and 组合 VIP 租户与延迟;以及保留其余请求的概率策略。随后配置前层 loadbalancing exporter,亲自计算缓冲内存并写入文件,最后编写包含该数值的 OpenTelemetryCollector CR。