
Когато в Linux сървър базата данни внезапно спре да работи, е необходимо да се намери причината. Причините могат да бъдат няколко. Например, SIGSEGV — срив поради бъг в бекенд сървъра. Но това е рядкост. Най-често просто свършва мястото на диска или паметта. Ако е свършило мястото на диска, единственото решение е да се освободи място и да се рестартира базата данни.
Out-Of-Memory Killer
Когато сървър или процесът свърши паметта, Linux предлага 2 решения: да срине цялата система или да завърши процеса (приложението), което използва паметта. По-добре е, разбира се, да се завърши процеса и да се спаси ОС от аварийно спиране. С две думи, Out-Of-Memory Killer е процес, който завършва приложението, за да спаси ядрото от срив. Той жертва приложението, за да запази работата на ОС. Нека първо обсъдим как работи OOM и как да го контролираме, а след това да видим как OOM Killer решава кое приложение да завърши.
Една от основните задачи на Linux е да предоставя памет на процесите, когато я поискат. Обикновено процесът или приложението искат памет от ОС, а самите те не я използват изцяло. Ако ОС предоставя памет на всички, които я искат, но не планират да я използват, много скоро паметта ще свърши и системата ще се откаже. За да се избегне това, ОС резервира памет за процеса, но всъщност не я предоставя. Паметта се предоставя само когато процесът наистина възнамерява да я използва. Случва се, че ОС няма свободна памет, но тя резервира памет за процеса, и когато на процеса му е необходима, ОС я предоставя, ако може. Недостатъкът е, че понякога ОС резервира памет, но в необходимия момент свободната памет я няма и системата се срива. OOM играе важна роля в този сценарий и завършва процеси, за да предпази ядрото от паника. Когато принудително се завърши процесът PostgreSQL, в логовете се появява съобщение:
Out of Memory: Killed process 12345 (postgres).Ако в системата има малко памет и не може да се освободи, се активира функцията out_of_memory. На този етап остава само едно — да завърши един или няколко процеса. OOM-killer трябва да прекрати процеса веднага или може да изчака? Очевидно е, че когато се извиква out_of_memory, това е свързано с изчакване на операция за вход-изход или суап на страницата на диска. Затова OOM-killer първо трябва да направи проверки и на тяхна основа да реши кой процес да прекрати. Ако всички посочени по-долу проверки дадат положителен резултат, OOM ще прекрати процеса.
Избор на процес
Когато паметта свърши, се извиква функцията out_of_memory(). В нея се съдържа функция select_bad_process(), която получава оценка от функцията badness(). Процесът, който е най-"лош", ще попадне под ударите. Функцията badness() избира процеса според определени правила.
- На ядрото му е необходима минимална памет за себе си.
- Трябва да се освободи много памет.
- Не е нужно да се прекратяват процеси, които използват малко памет.
- Необходимо е да се прекратят минимум процеси.
- Сложни алгоритми, които увеличават шансовете за прекратяване на тези процеси, които потребителят иска да завърши сам.
След като изпълни всички тези проверки, OOM разглежда оценката (oom_score). OOM назначава oom_score на всеки процес и след това умножава тази стойност по обема на паметта. Процесите с по-високи стойности имат по-големи шансове да станат жертви на OOM Killer. Процесите, свързани с привилегирования потребител, имат по-ниска оценка и по-малко шансове за принудително приключване.
postgres=# SELECT pg_backend_pid();
pg_backend_pid
----------------
3813
(1 ред)Идентификаторът на процеса Postgres е 3813, така че в друга конзола можете да получите оценката, използвайки този параметър на ядрото oom_score:
vagrant@vagrant:~$ sudo cat /proc/3813/oom_score
2Ако не искате изобщо OOM-Killer да прекрати процеса, има още един параметър на ядрото: oom_score_adj. Добавете голямо отрицателно число, за да намалите шансовете за прекратяване на важния за вас процес.
sudo echo -100 > /proc/3813/oom_score_adjЗа да зададете стойност oom_score_adj, задайте OOMScoreAdjust в блока на услугата:
[Service]
OOMScoreAdjust=-1000Или използвайте oomprotect в командата rcctl.
rcctl set servicename oomprotect -1000Принудително прекратяване на процеса
Когато един или повече процеси вече са избрани, OOM-Killer извиква функцията oom_kill_task(). Тази функция изпраща сигнал за приключване на процеса. При недостиг на памет oom_kill() извиква тази функция, за да изпрати на процеса сигнал SIGKILL. В ядрото се записва съобщение.
Няма памет: Убито е процеса [pid] [name].Как да контролираме OOM-Killer
В Linux можете да включвате и изключвате OOM-Killer (въпреки че последното не се препоръчва). За да го включите или изключите, използвайте параметъра vm.oom-kill. За да включите OOM-Killer в режим на изпълнение, изпълнете командата sysctl.
sudo -s sysctl -w vm.oom-kill = 1За да изключите OOM-Killer, задайте стойност 0 в същата команда:
sudo -s sysctl -w vm.oom-kill = 0Резултатът от тази команда няма да остане завинаги, а само до първото рестартиране. Ако искате повече постоянство, добавете тази линия в файла /etc/sysctl.conf:
echo vm.oom-kill = 1 >> /etc/sysctl.confОще един начин за включване и изключване е да напишете променливата panic_on_oom. Стойността винаги можете да проверите в /proc.
$ cat /proc/sys/vm/panic_on_oom
0Ако зададете стойност 0, то когато паметта свърши, ядрената паника няма да се случи.
$ echo 0 > /proc/sys/vm/panic_on_oomАко зададете стойност 1, то когато паметта свърши, ще се случи ядрената паника.
echo 1 > /proc/sys/vm/panic_on_oomOOM-Killer може не само да се включва и изключва. Вече говорихме, че Linux може да резервира за процесите повече памет, отколкото има, но да не я предоставя реално, а с това поведение управлява параметърът на ядрото на Linux. За това отговаря променливата vm.overcommit_memory.
Можете да зададете следните стойности за нея:
0: ядрото само решава, струва ли си да резервира твърде много памет. Това е стойността по подразбиране в повечето версии на Linux.
1: ядрото винаги ще резервира излишна памет. Това е рисковано, тъй като е вероятно паметта да свърши, защото вероятно в един момент процесите ще поискат необходимото.
2: ядрото няма да резервира повече памет, отколкото е зададено в параметъра overcommit_ratio.
В този параметър задавате процента памет, за който е допустимо излишното резервиране. Ако за него няма място, паметта не се предоставя, резервирането ще бъде отказано. Това е най-сигурният вариант, препоръчан за PostgreSQL. На OOM-Killer влияе и един елемент — възможността за подкачка, която се управлява от променливата cat /proc/sys/vm/swappiness. Тези стойности указват на ядрото как да обработва страниците за подкачка. Колкото по-висока е стойността, толкова по-малка е вероятността OOM да приключи процеса, но поради операции по вход-изход това оказва негативно влияние върху базата данни. И обратно — колкото по-ниска е стойността, толкова по-висока е вероятността OOM-Killer да се намеси, но и производителността на базата данни е по-висока. Стойността по подразбиране е 60, но ако цялата база данни се побира в паметта, е по-добре да зададете стойност 1.
Резюме
Не се страхувайте от „киллера“ в OOM-Killer. В този случай киллерът ще бъде спасител на вашата система. Той „убива“ най-злонамерените процеси и спасява системата от аварийно приключване. За да не се налага да използвате OOM-Killer за приключване на PostgreSQL, задайте на vm.overcommit_memory стойност 2. Това не гарантира, че OOM-Killer няма да се наложи да се намеси, но ще намали вероятността от принудително приключване на процеса PostgreSQL.
Източник: habr.com
