Späť na blog

OpenTelemetry Collector backpressure: dropy, memory_limiter a queue ako guardrails

Failure mode vyzerá ako “tracing je flaky”:

  • developeri tvrdia, že spany posielajú
  • backend (Tempo/Jaeger/OTLP endpoint) vyzerá zdravo
  • a napriek tomu traces miznú presne pri peaku
  • collector pody restartujú (OOMKilled) alebo ticho dropujú dáta

Mne sa to stalo presne vtedy, keď sme trace potrebovali najviac — počas incidentu.

Pointa je jednoduchá: telemetria musí byť best-effort a collector má byť nakonfigurovaný tak, aby vedel úmyselne zhadzovať dáta namiesto toho, aby umrel pod backpressure.

Testované na: OpenTelemetry Collector (contrib) 0.9x–0.10x, Kubernetes 1.29–1.31, OTLP cez gRPC, exportéry s retry + queue.

Incident (anonymizovaný)

Bežíme node-local collector ako DaemonSet (OTLP receiver), export do centrálneho gateway a potom do trace backendu. Pri traffic spiku:

  • ingest na backende sa spomalil (vyššia export latencia)
  • collector začal bufferovať viac
  • pamäť rástla až do OOMKill
  • po restarte sa to opakovalo
  • traces chýbali presne v intervale, ktorý sme debugovali

Blast radius: observability degradovalo pre celý cluster; metriky/logy ostali, ale trace-driven debugging bol slepý.

Constraint: v danom momente sme nevedeli “len doskalovať backend”. Potrebovali sme, aby collector ostal stabilný aj pri čiastočnej pomalosti backendu.

Timeline

  • T-0: on-call chce traces; coverage zrazu padne.
  • T+10m: collector pody majú rast pamäte; niektoré dostanú OOMKilled.
  • T+20m: v logoch je “dropping data” / “queue full”.
  • T+30m: potvrdíme exporter backpressure (slow sends, retry).
  • T+45m: mitigácia: zapnúť memory_limiter, doladiť queue, upraviť batch.
  • T+90m: pamäť sa stabilizuje; drop rate je bounded a viditeľný, nie katastrofický.

Mechanizmus: prečo collectory padajú (alebo ticho dropujú)

Backpressure je normálny — vy sa rozhodujete, ako prídete o dáta

Pipeline je v princípe:

receivers → processors → exporters

Keď exportéry spomalia:

  • queue sa plní
  • retry sa rozbehne
  • pamäť rastie (bufferované spany/logy/metriky)
  • nakoniec buď:
    • OOMKill (najhoršie; často stratíte ešte viac)
    • alebo controlled drop (lepšie)

Tail sampling zhoršuje pamäťový tlak

Tail sampling musí držať dáta, kým sa rozhodne. Kombinácia tail sampling + exporter backpressure + bez memory limiteru vie spraviť pamäťový cliff veľmi rýchlo.

“Nemáme chyby” ≠ “nemáme dropy”

Veľa tímov sleduje iba ingest na backende. Dropy ale môžu vzniknúť:

  • v exporter queue
  • v processoroch (memory limiter)
  • v exporter retry logike

Ak negrafujete “collector o collectore”, ste slepí.

Runbook: dokážte backpressure a dropy

Čo skontrolovať ako prvé

  1. Restarty a pamäť collectora
kubectl -n observability get pods -o wide
kubectl -n observability describe pod <otelcol-pod> | grep -n "OOMKilled\\|Restart" -n
kubectl -n observability top pod <otelcol-pod>
  1. Logy collectora v čase incidentu
kubectl -n observability logs <otelcol-pod> --since=30m | tail -n 200

Hľadám:

  • “dropping”
  • “queue is full”
  • “exporting failed”
  • “retrying”
  1. Pozrieť reálne metriky na /metrics (a nehádať názvy) Metriky sa medzi verziami menia; ja vždy najprv grepnem, čo collector vystavuje.
kubectl -n observability port-forward pod/<otelcol-pod> 8888:8888
curl -s http://127.0.0.1:8888/metrics | grep -E "^otelcol_" | head -n 50
curl -s http://127.0.0.1:8888/metrics | grep -E "exporter|queue|dropped|refused|failed" | head -n 50

Ako potvrdiť hypotézu

Chcete konzistentný príbeh:

  • export latencia rastie
  • queue utilization ide k limitu
  • accepted spany sú vysoké, ale “sent” zaostáva
  • “failed/dropped/refused” rastie
  • pamäť rastie (bez limiteru) alebo drop rastie (s limiterom)

Ak máte Prometheus, typicky grafujem:

  • accepted vs sent (by pipeline/exporter)
  • queue size/capacity
  • dropped/refused countery
  • RSS collectora

Použite presné názvy metrík, ktoré vidíte v /metrics.

Bezpečné mitigácie

  1. Zapnúť memory_limiter a dať ho skoro do pipeline Z “collector umrie” spravíte “collector dropuje kontrolovane”.

  2. Zapnúť sending queue na exportéri Aby krátke špičky absorboval bez retry búrky.

  3. Doladiť batch Príliš veľký batch vie spraviť latency spike aj memory spike. Príliš malý zas overhead.

  4. Dočasne znížiť load

  • znížiť sampling pre low-value telemetry
  • znížiť cardinalitu atribútov
  • vypnúť debug “log-to-span” mosty

Rizikové mitigácie

  • “Zväčšíme queue a bude to OK”
    • len zväčšíte blast radius, keď backend bude pomalý dlhšie než queue horizon
  • “Vypneme retries”
    • môžete zvýšiť drop (niekedy treba, ale vedome)
  • “Dáme file_storage všade”
    • viete presunúť incident z RAM na disk (a potom na evictions)

Čo sme zmenili (konkrétne)

Po zmene: memory limiter + batch tuning + exporter queue.

processors:
  memory_limiter:
    check_interval: 1s
    limit_percentage: 75
    spike_limit_percentage: 15
  batch:
    timeout: 1s
    send_batch_size: 2048
    send_batch_max_size: 4096

exporters:
  otlp:
    endpoint: otel-gateway.observability.svc.cluster.local:4317
    sending_queue:
      enabled: true
      num_consumers: 4
      queue_size: 10000
    retry_on_failure:
      enabled: true
      initial_interval: 200ms
      max_interval: 5s
      max_elapsed_time: 30s

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlp]

Dôležitá vec: memory_limiter musí byť pred batch (a aj pred tail samplingom, ak ho používate).

Ako verifikovať (merateľné)

  1. Pamäť je stabilná
  • RSS je flat aj pri peaku
  • žiadne OOMKills
  1. Dropy sú bounded a viditeľné
  • pri extrémnej pomalosti backendu môžete dropovať, ale kontrolovane
  1. Queue funguje ako tlmič
  • krátke špičky → queue sa naplní → potom sa vyprázdni
  • nemá byť pegged na 100% dlhé minúty
  1. Backend sa zotaví bez retry búrky
  • po zlepšení latency klesne retry rate

Prevencia / guardrails

  • Telemetry loss budget
    • akceptovateľná drop rate (napr. ≤ 0.1% v steady state; vyššia počas incidentu)
  • Collector SLO
    • bez restartov pri peaku
    • bounded memory pod backpressure
  • Sampling kontrakt
    • tail sampling vyžaduje sizing a pamäťový budget
  • Dashboardy a alerty
    • dropped/refused countery
    • queue utilization
    • exporter latency a retry rate

Súvisiace čítanie

Súvisiace články

Citujte tento článok

Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.

Michal Drozd. "OpenTelemetry Collector backpressure: dropy, memory_limiter a queue ako guardrails". https://www.michal-drozd.com/sk/blog/otel-collector-backpressure-memory-limiter/ (Publikované 4. decembra 2025).