Redis AOF fsync latency špičky: keď sa durabilita stane tvojím p99
Tento incident vyzerá ako “Redis je občas pomalý”, ale je bolestivo opakovateľný, keď vieš čo hľadať:
- p99 latencia špičkuje v burstoch (často každú sekundu alebo okolo persistence aktivity)
- CPU nie je pinned
- sieť je OK
- retry to maskuje, kým nespadne tail SLO
Ak máš Redis s AOF, existujú dvaja klasickí zabijaci latencie:
- fsync a disk contention (durabilita súperí so serving requestov)
- AOF rewrite fork CoW špičky (pamäťový tlak a paging počas BGREWRITEAOF)
Testované na: Redis 7.2–7.4, Linux 6.1–6.6, Kubernetes s PV storage (rýchle SSD aj pomalšie network disky).
Incident (anonymizovaný)
Zapli sme AOF na Redis inštancii, aby sme znížili data loss pri výpadku nodu. Okamžite:
- p99 išlo z pár ms na 50–300ms špičky
- počas rewrite okien vyskočilo RSS a pod sa blížil k OOM
- aplikácia začala retryovať a amplifikovať traffic
Constraint: AOF sme nemohli vypnúť. Bol to produktový requirement. Potrebovali sme persistenciu spraviť predvídateľnú a zabrániť tomu, aby rewrite spravil memory cliff.
Timeline
- T-0: p99 špičky sa objavia krátko po zapnutí AOF.
- T+10m:
INFO persistenceukáže rastaof_delayed_fsyncpočas špičiek. - T+20m: disk latencia koreluje so špičkami.
- T+30m: BGREWRITEAOF koreluje s RSS rastom (CoW správanie).
- T+45m: mitigácia: znížiť fsync contention počas rewrite a pridať memory headroom.
- T+2h: p99 sa stabilizuje; rewrite už nehrozí OOM.
- T+1d: guardrails: alerty na delayed fsync, fork time a rewrite frekvenciu.
Mechanizmus: odkiaľ prichádza latencia
AOF spraví z durability reálnu IO prácu
Pri AOF Redis appenduje write príkazy do AOF súboru a fsyncuje podľa politiky (appendfsync). Aj keď je fsync často asynchrónny, disk contention stále rozhoduje:
- filesystem a disk sú shared resource
- background write a fsync flush sa bijú s read/write requestami
- na pomalom disku dostaneš p99 špičky
Praktický signál je aof_delayed_fsync: “chceli sme fsync, ale nestihli sme”.
BGREWRITEAOF = fork + CoW
Rewrite vytvorí kompaktný AOF. Redis forkne:
- child zapisuje nový AOF
- parent ďalej obsluhuje traffic
- copy-on-write spraví pamäťové špičky pri modifikáciách stránok
Ak je memory headroom tesný, rewrite ťa vie zatlačiť do:
- reclaim stallov
- major faultov
- alebo OOMKilled
Runbook: dokáž, že príčina je AOF
1) Stav persistencie a delayed fsync
redis-cli INFO persistence | rg -n "aof_enabled|appendfsync|aof_delayed_fsync|aof_rewrite_in_progress|aof_current_size|aof_base_size|latest_fork_usec"
Sledujem:
aof_enabled:1appendfsyncpolitikaaof_delayed_fsyncrast pri špičkáchaof_rewrite_in_progress:1pri memory špičkáchlatest_fork_usec(fork budget)
2) Disk latencia
Na node je iostat najrýchlejšia pravda:
iostat -x 1 10
Ak await skáče pri špičkách, platíš storage latenciou v p99.
3) Memory headroom a OOM risk
V Kubernetes:
kubectl -n <ns> top pod <redis-pod>
kubectl -n <ns> describe pod <redis-pod> | rg -n "Limits|Requests|OOMKilled|Restart" -n
Ak BGREWRITEAOF tlačí RSS k limitu, potrebuješ headroom alebo inú persistence stratégiu.
Bezpečné mitigácie (praktické poradie)
1) Sane fsync politika
V praxi často appendfsync everysec (trade-off: približne do 1 sekundy data loss pri crash).
2) Znížiť fsync contention počas rewrite
Veľmi praktický knob:
no-appendfsync-on-rewrite yes
Zníži fsync tlak počas BGREWRITEAOF okien.
3) Rewrite thresholdy ako budget
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 512mb
Konkrétne čísla závisia od workloadu. Kontrakt je: rewrite frekvencia je bounded a vysvetliteľná.
4) Pamäťový headroom pre fork CoW
Ak nemáš CoW headroom, nemáš headroom na rewrite. V Kubernetes to často znamená:
- vyšší memory limit
- Guaranteed QoS (requests == limits) pre kritický Redis
- dedikovaný node pool
5) Predvídateľný disk
AOF na pomalom disku je p99 daň každý deň. Ak chceš durabilitu, zaplať za stabilnú latenciu.
Rizikové mitigácie
appendfsync no: mení durabilitu a data loss môže byť veľký.- opakovane zabíjať BGREWRITEAOF: vieš si vyrobiť rewrite backlog a ešte väčší rewrite neskôr.
- točiť knobs bez merania
aof_delayed_fsynca fork time: lietaš naslepo.
Čo sme zmenili (konkrétne)
1) Predvídateľná persistencia (config)
Reprezentatívny redis.conf:
appendonly yes
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 512mb
2) Explicitný memory headroom budget
Kritickú inštanciu sme spravili Guaranteed:
resources:
requests:
memory: "4Gi"
limits:
memory: "4Gi"
3) Storage so stabilnou latenciou
PV sme presunuli na storage class so stabilnou latenciou (alebo lokálne SSD, kde to dávalo zmysel).
4) Alerty, ktoré to chytia skoro
Alertujeme:
aof_delayed_fsyncnad baseline- fork time (
latest_fork_usec) nad budget - rewrite príliš často alebo príliš dlho
Ako verifikovať
- p99 je stabilnejšie (špičky sú zriedkavejšie a menšie).
aof_delayed_fsyncostáva okolo nuly.
redis-cli INFO persistence | rg -n "aof_delayed_fsync"
- BGREWRITEAOF už netlačí RSS k limitu.
Súvisiace čítanie
- Redis Memory Fragmentácia: Keď maxmemory Nestačí
- Redis Cluster Migrácia Slotov: Dočasná Explózia Pamäte
- Linux Page Cache Thrashing v Kontajneroch: Keď Voľná Pamäť Nie Je Voľná
- PostgreSQL checkpoint špičky: prečo p99 exploduje každých N minút
- Kubernetes OOM Killer: Prečo Kontajner Zomiera pri 50% Pamäte
- Structured Logging Performance: Keď Sa Logger Stane Bottleneckom
Súvisiace články
tcpdump vidí SYN, ale služba timeoutuje: pasca listen backlogu
Klienti timeoutujú, tcpdump ukazuje SYN (niekedy aj SYN-ACK), ale aplikácia nič neloguje. Častý vinník: Linux listen/accept fronty, ktoré sa pri load-e alebo CPU starvation preplnia.
ingress-nginx reload búrky: prečo 502 špičky sedia s Ingress churnom
Reloady NGINX Ingressu vedia dropovať keep-alive a robiť 502 špičky pri častých zmenách. Runbook na dôkaz reloadu, zníženie churnu a hardening.
Pod zaseknutý v Terminating: produkčný rozhodovací strom pre finalizery, volume a mŕtve nody
Konzervatívny runbook na bezpečné odblokovanie Terminating Podov: finalizery, CSI/volume cleanup, mŕtve nody a kedy (a ako) použiť force delete.
Kafka rebalance búrky: prečo scale-out consumerov vie zhoršiť lag
Kafka rebalance burky vedia zhoršiť lag pri scale-out. Runbook na max.poll, heartbeat, cooperative-sticky a config diffs, ktoré stabilizujú group.
Citujte tento článok
Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.