
Когато Linux сървърът на база данни спре неочаквано, е необходимо да се намери причината. Причините могат да бъдат няколко. Например, SIGSEGV — срив поради бъг в бекенд сървъра. Но това е рядкост. Най-често просто свършва дисковото пространство или паметта. Ако дисковото пространство свърши, единственият изход е да се освободи място и да се рестартира базата данни.
Out-Of-Memory Killer
Когато на сървър или процес свършва паметта, Linux предлага 2 начина за решение: да срине цялата система или да завърши процеса (приложението), което консумира памет. По-добре е, разбира се, да се завърши процеса и да се спаси ОС от аварийно затваряне. В две думи, Out-Of-Memory Killer е процес, който завършва приложение, за да спаси ядрото от срив. Той жертва приложението, за да съхрани работата на ОС. Нека първо обсъдим как работи OOM и как да го контролираме, а след това да видим как OOM Killer решава кое приложение да завърши.
Една от основните задачи на Linux е да разпределя памет на процесите, когато те я искат. Обикновено процесът или приложението искат памет от ОС, а самите те я използват не напълно. Ако ОС предоставя памет на всички, които я искат, но не планират да я използват, много скоро паметта ще свърши и системата ще откаже. За да избегне това, ОС резервира памет за процеса, но на практика не я предоставя. Паметта се дава само когато процесът наистина е готов да я използва. Случва се, че ОС няма свободна памет, но резервира памет за процеса, и когато на процеса му е необходима, ОС я предоставя, ако може. Минусът е, че понякога ОС резервира памет, но в нужния момент свободната памет не е налична и системата се срива. OOM играе важна роля в този сценарий и завършва процеси, за да предпази ядрото от паника. Когато процесът PostgreSQL бъде принудително завършен, в логовете се появява съобщение:
Out of Memory: Убита е процес 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. В логовете на ядрото се записва съобщение.
Out of Memory: Убити процес [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, то когато паметта свърши, няма да има kernel panic.
$ echo 0 > /proc/sys/vm/panic_on_oomАко зададете стойност 1, то когато паметта свърши, ще настъпи kernel panic.
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
