Конфигуриране на Out-Of-Memory Killer в Linux за PostgreSQL

Конфигуриране на Out-Of-Memory Killer в Linux за PostgreSQL

Когато 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() избира процес по определени правила.

  1. Ядрото се нуждае от минимално количество памет за себе си.
  2. Необходимо е да се освободи много памет.
  3. Не е нужно да се прекратяват процеси, които използват малко памет.
  4. Необходимо е да се завърши минимален брой процеси.
  5. Сложни алгоритми, които увеличават шансовете за прекратяване на тези процеси, които потребителят сам иска да завърши.

След извършването на всички тези проверки, 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_oom

OOM-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

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster