Envoy/Istio 503 UF/UO/UT: keď výpadok robí mesh, nie aplikácia
Symptómy vyzerajú ako “appka je flaky”, kým nepozrieš správne miesto:
- klienti vidia bursty HTTP 503 (niekedy 504)
- pody sú Ready, CPU nie je extrém
- retry často “opraví” request
- v response je
server: envoyax-envoy-response-flags
Kľúčový posun: v service meshi je Envoy produkčný komponent. Má vlastné connection pooly, limity na queue, retry a outlier ejection. Ak sú zle nastavené (alebo retry znásobuje load), Envoy sa stane bottleneck aj keď appka je OK.
Testované na: Kubernetes 1.29–1.31, Istio 1.21–1.24, Envoy 1.28–1.30, HTTP/1.1 + HTTP/2, sidecary aj ingress gateway.
Incident (anonymizovaný)
Služba bola stabilná mesiace. Potom prišla “malá” zmena v Istio policy:
- DestinationRule s konzervatívnymi pool limitmi (copy-paste)
- retries ostali zapnuté s veľkým per-try timeoutom
- outlier detection bolo agresívne
Pri peaku:
- Envoy začal vracať 503
- app metriky vyzerali normálne (appka už ani nedostávala requesty)
- retry znásobovalo load na proxy vrstve
- vyzeralo to “náhodne”, lebo to záviselo od proxy loadu na konkrétnych podoch
Constraint: mesh sme nemohli vypnúť v incidente. Potrebovali sme bezpečný patch, ktorý okamžite zníži mesh tlak.
Timeline
- T-0: 503 spike; p99 rastie.
- T+10m: potvrdím, že 503 má Envoy flags (
x-envoy-response-flags). - T+20m: Envoy admin stats ukážu pending overflow + upstream connection overflow.
- T+30m: nájdem DestinationRule s nízkymi limitmi a retry amplifikáciou.
- T+40m: mitigácia: znížiť retries + zvýšiť connection pool budget pre jednu službu.
- T+60m: 503 prestanú; p99 sa stabilizuje.
- T+1d: pridáme “mesh kontrakty” v CI: zakázať malé pool limity pre kritické služby a cap retries.
Mechanizmus: čo vlastne znamenajú Envoy flags
Envoy dáva clues v access logoch aj headeroch. Flags sú užitočné, lebo mapujú priamo na triedu príčiny.
Rýchly decoder (najčastejšie v incidentoch):
| Flag | Čo to obvykle znamená | Typická príčina | Prvý check |
|---|---|---|---|
UF | upstream connection failure | no healthy upstream, connect error, TLS mismatch, blackhole | health, mTLS/TLS, network |
UO | upstream overflow | connection pool / pending queue overflow | pool limity, pending requests, retries |
UT | upstream request timeout | per-try timeout príliš nízky, upstream pomalý, queueing | timeouty, queue depth, backend p99 |
NR | no route | route mismatch | VirtualService config |
Často uvidíš viac flags naraz. Ja idem: flag → hypotéza → potvrdenie cez proxy stats.
Runbook: diagnostika a oprava mesh 503
Čo skontrolovať ako prvé
1) Dokáž, že 503 robí Envoy
Z klienta/debug podu pozri headery:
curl -s -D- http://<service>.<ns>.svc.cluster.local/health -o /dev/null | sed -n '1,20p'
Hľadaj:
server: envoyx-envoy-response-flags: ...
2) Vytiahni Envoy stats zo sidecaru
Najrýchlejšia odpoveď “je Envoy overloadnutý?” je v admin stats na 15000.
kubectl -n <ns> exec -it <pod> -c istio-proxy -- sh -lc \
"curl -s http://127.0.0.1:15000/stats | egrep 'upstream_rq_pending_overflow|upstream_cx_overflow|upstream_rq_timeout|no_healthy_upstream' | head -n 50"
Ak upstream_rq_pending_overflow alebo upstream_cx_overflow rastú pri incidente, nerobíš app debug — robíš proxy budget debug.
3) Nájsť relevantný Istio config (DestinationRule / VirtualService)
Tu je väčšina root cause.
kubectl -n <ns> get destinationrule,virtualservice
kubectl -n <ns> get destinationrule <dr> -o yaml
kubectl -n <ns> get virtualservice <vs> -o yaml
Ak používaš istioctl, pozrieš “effective” config rýchlejšie:
istioctl proxy-config clusters <pod> -n <ns> | head -n 40
istioctl proxy-config routes <pod> -n <ns> | head -n 40
Ako potvrdiť hypotézu
Vyber dominujúci flag a potvrď:
UO→ overflow stats + malé limity v DestinationRuleUT→ per-try timeout vs backend p99 + queue depthUF→ upstream health + mTLS/TLS kompatibilitaNR→ routes/hosts
Častá postupnosť:
- zníž retries → overflow zmizne → 503 padnú
- potom pools nastav rozumne (nie “retries off navždy”)
Bezpečné mitigácie (v incidente)
1) Zníž retry amplifikáciu
Retries sú multiplikátor. 1 request sa zmení na 3 upstream pokusy → 3× load na proxy aj backend.
Bezpečná emergency zmena je cap retries a malý perTryTimeout:
retries:
attempts: 1
perTryTimeout: 1s
retryOn: gateway-error,connect-failure,refused-stream
timeout: 3s
2) Zvýš connection pool budget pre hot službu
Ak vidíš overflow counters, zvýš limity pre jednu službu.
3) Dočasne uvoľni outlier detection
Agresívne ejection vie spraviť feedback loop:
- pár 5xx → ejection → menej endpointov → overload → viac 5xx
V incidente zníž citlivosť alebo dočasne vypni pre službu.
Rizikové mitigácie
- “infinite” pool limity všade
- posunieš bottleneck na node/kernel a spravíš väčší incident
- vypnúť mTLS aby sa opravilo
UF- môžeš spraviť security incident a stále to nebude fix
- vyhodiť sidecary
- veľký blast radius a zlý rollback
Čo sme zmenili (konkrétne)
1) Nastavili sme connection pool ako budget
Chyba bol malý pool limit z copy-pastu. Nahradili sme ho budgetom podľa:
- concurrency
- upstream latency
- headroom na bursty
Príklad DestinationRule:
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: payments
spec:
host: payments.<ns>.svc.cluster.local
trafficPolicy:
connectionPool:
tcp:
maxConnections: 500
http:
http1MaxPendingRequests: 2000
maxRequestsPerConnection: 1000
2) Retries a timeouty sme spravili explicitne
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: payments
spec:
hosts:
- payments.<ns>.svc.cluster.local
http:
- timeout: 3s
retries:
attempts: 1
perTryTimeout: 1s
retryOn: gateway-error,connect-failure,refused-stream
route:
- destination:
host: payments.<ns>.svc.cluster.local
3) “Mesh kontrakt” lint v CI
Lintujeme Istio configy:
- zakázať malé
maxConnectionspre kritické služby bez “justification” - cap retries a povinné explicitné timeouty
- zákaz agresívnych outlier defaults v šablónach
Ako verifikovať (merateľné)
1) Overflow counters prestanú rásť
kubectl -n <ns> exec -it <pod> -c istio-proxy -- sh -lc \
"curl -s http://127.0.0.1:15000/stats | egrep 'upstream_rq_pending_overflow|upstream_cx_overflow' | head -n 20"
Očakávam: counters sa po aplikovaní configu rýchlo prestanú zvyšovať.
2) x-envoy-response-flags zmiznú
Ak chyby ostanú, majú byť backend chyby, nie proxy overflow.
3) p99 stabilne bez toho, aby to len “skryl retry”
Sleduj p99 aj request rate. Ak sa p99 “zlepší” ale traffic padne, len si presunul bottleneck.
Prevencia / guardrails
- Budžety
- per-service pool budget + retry budget
- Invarianta
- “kritická služba musí prežiť 1 endpoint loss bez UO”
- Alerty
- overflow counters, no_healthy_upstream, queue depth
- Zmeny
- DestinationRule/VirtualService šablóny sú produkčný kód (review ako kód)
Súvisiace čítanie
- gRPC Keepalive Nezhoda: Transport Closing Po Idle
- gRPC Deadline Propagácia: Prevencia Kaskádových Zlyhaní
- Circuit Breaker Anti-Patterns: Keď Ochrana Spôsobuje Výpadky
- Circuit Breaker vs Rate Limiter vs Bulkhead: Kedy Ktorý Pattern Použiť
- Kubernetes graceful shutdown ako kontrakt: nula 502 počas rolloutov (HTTP + gRPC)
- PMTU Blackholes: Keď Iba Veľké Odpovede Visia
- Adaptive Concurrency Limits: Prestaňte Hádať Veľkosti Thread Poolov
Súvisiace články
Envoy outlier detection brownouty: keď mesh vyhodí zdravé pody
Debug Istio/Envoy outlier detection brownoutov: prečo mesh vyhadzuje zdravé pody a rastú 503 v produkcii. Obsahuje xDS checks, bezpečné fixy a alerty.
Vyčerpanie Ephemeral Portov: Node Ktorý 'Pokazí'
Jeden Kubernetes node začne zlyhávať pripojenia k externým službám zatiaľ čo pody vyzerajú zdravé. Skrytá príčina: sidecar proxy vyčerpávajú ephemeral porty krátkodobými spojeniami.
Kubernetes APF vyhladovanie: keď jeden controller zablokuje kubectl
APF vie vyhladovať Kubernetes API: kubectl visí, controllery timeoutujú a rastú 429. Runbook na izoláciu klienta, úpravu FlowSchema a verifikáciu.
Kubernetes OOM Killer: Prečo Kontajner Zomiera pri 50% Pamäte
Kontajner má 4GB memory limit ale OOM kill pri 2GB used. Kernel buffers, page cache a cgroup accounting triky spôsobujú skoré OOMKills. Tu je celý obraz.
Citujte tento článok
Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.