先把当时的情况摆出来。OTel Collector 0.110 部署在 2C4G 的边缘节点,memory_limiter 限制 512MiB,流量高峰后 span 数量少了四成,Collector 自身没有 OOM,日志里只有一行 soft limit exceeded,后端 Tempo 看不到告警。

真正麻烦的地方在于,几个原因的现象几乎一样。memory_limiter 触发后直接丢数据而不是背压。还有一种是batch processor 队列过大,先把内存撑满。

不容易想到的是,sending_queue 没开持久化,重启即丢。还有一种情况,采样率在前端已固定,Collector 只能整批丢。

先看 Collector 的限流相关指标

curl -s http://localhost:8888/metrics | grep -i memory_limiter

再往下确认 batch 和 queue 的配置

grep -A6 'batch:' config.yaml

然后把 limit 提到 1GiB 并开启持久化队列

python -c "print('sending_queue:\n  storage: file_storage')"

压测后对比入口与出口的 span 计数

curl -s http://localhost:8888/metrics | grep -E 'receiver_accepted_spans|exporter_sent_spans'

怎么算真的好了,看的是同一批现象。压测期间入口和出口的 span 计数差值控制在 1% 以内,soft limit 日志不再出现,Tempo 里能查到完整的调用链。

这里还有个坑。memory_limiter 的语义是丢数据保进程,适合边缘但不适合审计链路;要么提高内存并持久化队列,要么在前端降采样,不能只看进程还活着。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。

作者 9823189