Späť na blog

Envoy/Istio 503 UF/UO/UT: keď výpadok robí mesh, nie aplikácia

|
| kubernetes, istio, envoy, service-mesh, debugging

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: envoy a x-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íčinaPrvý check
UFupstream connection failureno healthy upstream, connect error, TLS mismatch, blackholehealth, mTLS/TLS, network
UOupstream overflowconnection pool / pending queue overflowpool limity, pending requests, retries
UTupstream request timeoutper-try timeout príliš nízky, upstream pomalý, queueingtimeouty, queue depth, backend p99
NRno routeroute mismatchVirtualService 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: envoy
  • x-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 DestinationRule
  • UT → per-try timeout vs backend p99 + queue depth
  • UF → upstream health + mTLS/TLS kompatibilita
  • NR → 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é maxConnections pre 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

Súvisiace články

Citujte tento článok

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

Michal Drozd. "Envoy/Istio 503 UF/UO/UT: keď výpadok robí mesh, nie aplikácia". https://www.michal-drozd.com/sk/blog/envoy-istio-503-uf-uo-ut/ (Publikované 2. novembra 2025).