Postgres – všetko, čo si chcel vedieť, ale bál sa spýtať svojho seniora, aby si nevypadal ako jelito 15. OOM killer.
OOM killer je štandardná linuxová vec v managemente pamäte. Vzhľadom na to, že linux používa virtual memory a má necnosť, že dovoľuje alokovať aplikácii viac pamäte, než má k dispozícii (overcommit), občas je nutné nejaký proces odstreliť, keď pamäť dôjde. Ovšem postgres má tú vlastnosť, že ak sa odstrelí čo jen 1 process SIGKILLom (napr. nejaký enormný dotaz), tak sa porúča celý cluster, ktorý nevie, v akom stave sú datové buffers. Ergo OOM killer na postgres je veľký špatný…
Overcommit
Overcomitovanie pamäte je výsledkom “dobrej praxe”, že aplikácie si po sebe dobre upratajú a málokedy dôjde k súbežnému vyžraniu pamäte viecerými procesmi. No, ale keď k tomu dôjde, tak OOM killer. Overcommitovanie je nastaviteľné a to parametrom v /proc/sys/vm/overcommit_memory
Hodnoty:
- 0 = kernel má voľnú ruku v rozhodovaní, či bude overcommitovať. Default.
- 1 = kernel bude vždy overcommitovať
- 2 = kernel nikdy nebude overcommitovať cez threshold definovaný v /proc/sys/vm/overcommit_ratio. Doporučené pre postgresový stroj.
Ako OOM killer vlastne pracuje
- Keď je systém out of memory, tak kernel volá funkciu out_of_memory() a tá v rámci reťaze rozhodovania funkciu badness(). Táto funkcia rozhodne, ktorý proces si zaslúži byť položený na oltár uvoľnenia pamäte a to na základe počítania skóre (čím vyššie, tým je proces lepší adept na odstrel):
- bude uprednostneny proces non-privileged usera
- vyber proces, kde sa jedným odstrelom zvýši čo najviac pamäte
- prednosť na popravisko má proces spustený nedávno
- atď…
Oom_score sa dá ľahko vylistovať (cat /proc/PID/oom_score/). Čím vyššie skóre, tým pravdepodobnejší zostrel. Po vyrátaní “badness” sa spustí funkcia oom_kill() a je hotovo…
Ako znížiť OOM skóre a “imunizovať” proces
1. OOM killer sa dá úplne vypnúť (nedoporučuje sa, pamäť pôjde do swapu a potom buch celý stroj):
sysctl -w vm.oom-kill = 0 (resp. echo vm.oom-kill = 0 >>/etc/sysctl.conf)
2. Umelo znížiť oom skóre flagom v /proc/PID/oom_score_adj (čím zápornejšia hodnota, tým lepšia imunizácia), ale to je dosť nepohodlné, pretože apriori nevieme, aký PID bude mať napr. postgres.
3. Zakázať overcommit (ansible yaml):
– name: create /etc/sysctl.d/memory_overcommit.conf
template:
src: memory_overcommit.conf.j2
dest: /etc/sysctl.d/memory_overcommit.conf
notify: memory overcommit customization
tags: postgres_memory_overcommit
a odpovedajúca džindža:
vm.overcommit_memory = 2
Ako nájsť v logoch, že OOM killer zapracoval
OOM killer je kernelová vec (skús lsof /dev/kmsg, kto načúva), takže bude najčastešie niekde v /var/log/kern.log (grep -i “kill”). Pokiaľ sa naň príde rýchlo, skôr než sa zaplní kruhový buffer kernelu, tak v dmesg.
Pre journald/journalctl doporučujem tento krátky postup.