memory_limiter 为什么排最前,batch 为什么排最后
一句话总结
Collector 配置中,处理器在 pipeline 里的排列顺序,就是信号实际经过的处理顺序。这句话虽短,生产影响却很大:memory_limiter 放最前,batch 放最后,tail_sampling 位于 batch 前,敏感信息删除则应放在添加元数据的处理器之后。
为什么需要它
SDK 直发后端也能工作,但部署 Collector 有五个理由。
- 无需重新部署即可改变策略。 采样率、属性过滤和保留对象都需在运行中调整;若放在应用环境变量中,就要滚动更新 20 个服务。
- 把应用与后端故障隔离。 后端变慢时,SDK 发送队列堆积,应用内存上升;Collector 可代为承受压力。
- 可以更换后端。 按信号使用不同目的地或并行运行两个后端,都只需改一处配置。
- 在应用外删除敏感信息。 令牌或邮箱混入属性的事故一定会发生。有 Collector 防线后,响应方式是改配置而非重新部署。
- 可以尾部采样。 根据追踪结果作决定,需要把 span 汇集到一处,而这个位置不能是应用。
工作原理
配置有六个顶层区段:receivers、processors、exporters、connectors、extensions、service。关键是,在前五处只定义组件并不会启用它;必须在 service.pipelines 中引用(扩展在 service.extensions),它才真正工作。配置全写完却毫无效果的事故,有一半源自这里。
connectors 把一个 pipeline 的输出接到另一个 pipeline 的输入。从 trace 生成 RED 指标的 spanmetrics 是典型例子。它既是 exporter 又是 receiver,因此拥有独立区段。
逐项看顺序造成的差异。
memory_limiter必须最先,因为它不是缩减数据,而是在发现内存压力时直接拒绝并把 backpressure 传回上游。放在后面,解析和转换已经耗尽内存,保护便失去意义。tail_sampling必须位于batch前。采样按 trace 决定;若先 batch,同一 trace 的 span 会散到不同批次,决策对象不再完整。batch几乎总在最后。batch它服务于传输效率,后面再加处理会造成拆包重组的浪费。- 删除与哈希的顺序要反过来思考。
k8sattributes等元数据处理器会新建属性,所以删除必须在其后,才能无遗漏应用。
memory_limiter 的取值有常用惯例。
| 容器内存 | limit_mib |
spike_limit_mib |
GOMEMLIMIT |
|---|---|---|---|
| 1Gi | 820 | 164 | 656MiB |
| 2Gi | 1638 | 328 | 1310MiB |
| 4Gi | 3276 | 655 | 2621MiB |
limit_mib 约为容器上限的 80%,spike_limit_mib 为其 20%。若 limit_mib 高于容器上限,处理器介入前内核就会杀死进程。
batch 的常见错误是把 send_batch_size 当成上限。它只是“积累到该数量就立即发送”的触发值,真正上限是 send_batch_max_size。不指定后者,批次可能远大于预期。
现场会遇到的情况
症状分三类。
完全没有数据进入。 临时添加 debug exporter,先确认是否到达 receiver。接收指标为 0,表示应用尚未发送或地址错误;最常见原因是写反 gRPC 与 HTTP 端口。
数据进入了,后端却没有。 先看发送失败指标;没有失败仍消失,则看队列和拒绝指标。tail_sampling 经常是原因。策略过于激进时,数据正常发送,但后端只缺某些 trace,且指标完全不报异常。暂时从 pipeline 移除它再复现,是最快区分法。
周期性退出。 多半是内存压力。已有 memory_limiter 仍退出,应怀疑其上限与容器限制不匹配。
自身指标分三阶段读取:接收看 otelcol_receiver_accepted_spans 与 otelcol_receiver_refused_spans;处理比较 otelcol_processor_incoming_items 与 outgoing_items;发送看 otelcol_exporter_sent_spans、send_failed_spans、enqueue_failed_spans,以及 queue_size 与 queue_capacity 比率。若只能设一个告警,就选择队列指标。 队列持续贴近容量后,接下来几乎总是拒绝与丢失。
下一实验要做什么
从头编写 /root/otca-collector/config.yaml:OTLP receiver 的两个端口、按容器上限 80% 设置的 memory_limiter、Kubernetes 元数据附加、敏感属性删除与哈希、同时指定触发值和上限的 batch、启用队列和重试的 exporter、health_check 与 zpages 扩展,以及遵守处理器顺序的三个 pipeline。