Keď sa databázový server neočakávane ukončí v systéme Linux, musíte nájsť príčinu. Dôvodov môže byť viacero. Napríklad, SIGSEGV — zlyhanie v dôsledku chyby na backend serveri. Ale to je zriedkavé. Najčastejšie vám jednoducho dôjde miesto na disku alebo pamäť. Ak vám dôjde miesto na disku, existuje len jedna cesta von – uvoľniť miesto a reštartovať databázu.
Zabijak s nedostatkom pamäte
Keď serveri alebo procesu dôjde pamäť, Linux ponúka 2 riešenia: zrútenie celého systému alebo ukončenie procesu (aplikácie), ktorý zaberá pamäť. Je lepšie, samozrejme, ukončiť proces a zachrániť OS pred pádom. Stručne povedané, Out-Of-Memory Killer je proces, ktorý zabije aplikáciu, aby zachránil jadro pred pádom. Obetuje aplikáciu, aby udržal operačný systém v chode. Najprv si pohovorme o tom, ako OOM funguje a ako ho ovládať, a potom uvidíme, ako sa OOM Killer rozhoduje, ktorú aplikáciu ukončiť.
Jednou z hlavných úloh Linuxu je alokovať pamäť procesom, keď o to požiadajú. Proces alebo aplikácia zvyčajne vyžaduje pamäť od operačného systému, ale nevyužíva ju v plnej miere. Ak OS rozdá pamäť každému, kto o ňu požiada, ale neplánuje ju použiť, veľmi skoro sa pamäť minie a systém zlyhá. Aby sa tomu zabránilo, operačný systém vyhradí pamäť pre proces, ale v skutočnosti ju neuvoľní. Pamäť sa prideľuje iba vtedy, keď ju proces skutočne použije. Stáva sa, že OS nemá voľnú pamäť, ale priraďuje pamäť procesu a keď ju proces potrebuje, OS ju pridelí, ak môže. Nevýhodou je, že niekedy operačný systém vyhradí pamäť, ale v správnom čase nie je voľná pamäť a systém sa zrúti. OOM hrá v tomto scenári dôležitú úlohu a ukončuje procesy, aby sa zabránilo panike jadra. Keď je proces PostgreSQL nútený ukončiť, v protokole sa zobrazí správa:
Out of Memory: Killed process 12345 (postgres).
Ak má systém málo pamäte a nemožno ju uvoľniť, funkcia sa zavolá out_of_memory
. V tejto fáze jej ostáva už len jedna vec – dokončiť jeden alebo viacero procesov. Mal by OOM-killer ukončiť proces okamžite alebo môže počkať? Je zrejmé, že keď sa volá out_of_memory, je to kvôli čakaniu na I/O operáciu alebo stránkovanie na disk. OOM zabijak preto musí najskôr vykonať kontroly a na ich základe rozhodnúť, že je potrebné proces ukončiť. Ak sú všetky nižšie uvedené kontroly pozitívne, OOM proces ukončí.
Výber procesu
Keď dôjde pamäť, zavolá sa funkcia out_of_memory()
. Má funkciu select_bad_process()
, ktorý dostáva hodnotenie od funkcie badness()
. Zameria sa na „najhorší“ proces. Funkcia badness()
vyberá proces podľa určitých pravidiel.
- Jadro potrebuje pre seba určitú minimálnu pamäť.
- Potrebujete uvoľniť veľa pamäte.
- Nie je potrebné ukončiť procesy, ktoré využívajú málo pamäte.
- Je potrebné dokončiť minimálne procesy.
- Komplexné algoritmy, ktoré zvyšujú šance na dokončenie tých procesov, ktoré chce používateľ sám dokončiť.
Po dokončení všetkých týchto kontrol OOM preskúma skóre (oom_score
). OOM menuje oom_score
každý proces a potom túto hodnotu vynásobí množstvom pamäte. Procesy s väčšími hodnotami sa s väčšou pravdepodobnosťou stanú obeťou OOM Killera. Procesy spojené s užívateľom root majú nižšie skóre a je menej pravdepodobné, že budú nútené ukončiť.
postgres=# SELECT pg_backend_pid();
pg_backend_pid
----------------
3813
(1 row)
ID procesu Postgres je 3813, takže v inom prostredí je možné získať skóre pomocou tohto parametra jadra oom_score
:
vagrant@vagrant:~$ sudo cat /proc/3813/oom_score
2
Ak nechcete, aby OOM-Killer vôbec zabil proces, existuje ďalšia možnosť jadra: oom_score_adj
. Pridajte veľkú zápornú hodnotu, aby ste znížili šance na dokončenie procesu, ktorý si ceníte.
sudo echo -100 > /proc/3813/oom_score_adj
Ak chcete nastaviť hodnotu oom_score_adj
, nastavte OOMScoreAdjust v bloku služieb:
[Service]
OOMScoreAdjust=-1000
Alebo použite oomprotect
v tíme rcctl
.
rcctl set <i>servicename</i> oomprotect -1000
Vynútiť ukončenie procesu
Keď je už vybratý jeden alebo viac procesov, OOM-Killer zavolá funkciu oom_kill_task()
. Táto funkcia vyšle do procesu signál ukončenia. V prípade nedostatku pamäte oom_kill()
Volá túto funkciu na odoslanie signálu SIGKILL do procesu. Do protokolu jadra sa zapíše správa.
Out of Memory: Killed process [pid] [name].
Ako ovládať OOM-Killer
V systéme Linux môžete povoliť alebo zakázať OOM-Killer (hoci druhý sa neodporúča). Ak chcete povoliť alebo zakázať, použite parameter vm.oom-kill
. Ak chcete povoliť OOM-Killer za behu, spustite príkaz sysctl
.
sudo -s sysctl -w vm.oom-kill = 1
Ak chcete vypnúť OOM-Killer, zadajte hodnotu 0 v rovnakom príkaze:
sudo -s sysctl -w vm.oom-kill = 0
Výsledok tohto príkazu sa neuloží navždy, ale iba do prvého reštartu. Ak potrebujete väčšiu vytrvalosť, pridajte tento riadok do súboru /etc/sysctl.conf
:
echo vm.oom-kill = 1 >>/etc/sysctl.conf
Ďalším spôsobom aktivácie a deaktivácie je napísanie premennej panic_on_oom
. Hodnotu je možné vždy skontrolovať /proc
.
$ cat /proc/sys/vm/panic_on_oom
0
Ak nastavíte hodnotu na 0, potom keď sa minie pamäť, nedôjde k panike jadra.
$ echo 0 > /proc/sys/vm/panic_on_oom
Ak nastavíte hodnotu na 1, potom keď sa minie pamäť, dôjde k panike jadra.
echo 1 > /proc/sys/vm/panic_on_oom
OOM-Killer sa dá nielen zapnúť a vypnúť. Už sme povedali, že Linux dokáže vyhradiť viac pamäte pre procesy, než je k dispozícii bez toho, aby ju skutočne pridelil, a toto správanie je riadené parametrom linuxového jadra. Za to je zodpovedná premenná vm.overcommit_memory
.
Môžete preň zadať nasledujúce hodnoty:
0: Samotné jadro sa rozhodne, či si vyhradí príliš veľa pamäte. Toto je predvolené nastavenie vo väčšine verzií Linuxu.
1: Jadro si vždy vyhradí dodatočnú pamäť. Je to riskantné, pretože sa môže vyčerpať pamäť, pretože s najväčšou pravdepodobnosťou to jedného dňa procesy budú vyžadovať.
2: jadro si nevyhradí viac pamäte, ako je uvedené v parametri overcommit_ratio
.
Pomocou tohto parametra zadáte percento pamäte, ktorá môže byť nadmerne rezervovaná. Ak na to nie je miesto, nepridelí sa žiadna pamäť a rezervácia bude zamietnutá. Toto je najbezpečnejšia možnosť odporúčaná pre PostgreSQL. OOM-Killer je ovplyvnený ďalším prvkom - schopnosťou swapovania, ktorá je riadená premennou cat /proc/sys/vm/swappiness
. Tieto hodnoty hovoria jadru, ako zaobchádzať so stránkovaním. Čím vyššia je hodnota, tým je menšia pravdepodobnosť, že OOM ukončí proces, ale kvôli I/O operáciám to má negatívny vplyv na databázu. A naopak – čím je hodnota nižšia, tým je vyššia pravdepodobnosť zásahu OOM-Killer, ale vyšší je aj výkon databázy. Predvolená hodnota je 60, ale ak sa celá databáza zmestí do pamäte, je lepšie nastaviť hodnotu na 1.
Výsledky
Nenechajte sa vystrašiť „zabijakom“ v OOM-Killer. V tomto prípade bude vrahom záchranca vášho systému. „Zabije“ najhoršie procesy a ochráni systém pred pádom. Aby ste nemuseli používať OOM-Killer na ukončenie PostgreSQL, nastavte na vm.overcommit_memory
hodnota 2. To nezaručuje, že OOM-Killer nebude musieť zasiahnuť, ale zníži sa tým pravdepodobnosť vynútenia ukončenia procesu PostgreSQL.
Zdroj: hab.com