Когато сървър на база данни се затвори неочаквано в Linux, трябва да намерите причината. Може да има няколко причини. Например, SIGSEGV — повреда поради грешка в бекенд сървъра. Но това е рядкост. Най-често просто ви липсва дисково пространство или памет. Ако ви свърши дисковото пространство, има само един изход - освободете място и рестартирайте базата данни.
Убиец на липса на памет
Когато на сървър или процес свърши паметта, 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, това се дължи на изчакване на I/O операция или пейджинг на диск. Следователно убиецът на OOM трябва първо да извърши проверки и въз основа на тях да реши, че процесът трябва да бъде прекратен. Ако всички проверки по-долу са положителни, OOM ще прекрати процеса.
Избор на процес
Когато паметта свърши, функцията се извиква out_of_memory()
. Има функция select_bad_process()
, който получава оценка от функцията badness()
. „Най-лошият“ процес ще бъде насочен. функция badness()
избира процес според определени правила.
- Ядрото се нуждае от минимална памет за себе си.
- Трябва да освободите много памет.
- Няма нужда да прекратявате процеси, които използват малко памет.
- Трябва да бъдат завършени минимални процеси.
- Комплексни алгоритми, които увеличават шансовете за завършване на тези процеси, които самият потребител иска да завърши.
След като завърши всички тези проверки, OOM проверява резултата (oom_score
). ООМ назначава oom_score
всеки процес и след това умножава тази стойност по количеството памет. Процесите с по-големи стойности е по-вероятно да станат жертва на OOM Killer. Процесите, свързани с root потребителя, имат по-нисък резултат и е по-малко вероятно да бъдат принудени да прекратят.
postgres=# SELECT pg_backend_pid();
pg_backend_pid
----------------
3813
(1 row)
Идентификаторът на процеса на 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 <i>servicename</i> oomprotect -1000
Принудително прекратяване на процес
Когато един или повече процеси вече са избрани, OOM-Killer извиква функцията oom_kill_task()
. Тази функция изпраща сигнал за прекратяване на процеса. В случай на недостиг на памет oom_kill()
Извиква тази функция, за да изпрати сигнал SIGKILL към процеса. В регистрационния файл на ядрото се записва съобщение.
Out of Memory: Killed process [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_oom
OOM-Killer може не само да се включва и изключва. Вече казахме, че Linux може да резервира повече памет за процеси, отколкото е налична, без реално да я разпределя, и това поведение се контролира от параметър на ядрото на Linux. Променливата е отговорна за това vm.overcommit_memory
.
Можете да посочите следните стойности за него:
0: Самото ядро решава дали да резервира твърде много памет. Това е по подразбиране за повечето версии на Linux.
1: Ядрото винаги ще резервира допълнителна памет. Това е рисковано, защото паметта може да свърши, защото най-вероятно един ден процесите ще го изискват.
2: ядрото няма да резервира повече памет от посоченото в параметъра overcommit_ratio
.
С този параметър вие определяте процента на паметта, който е разрешено да бъде свръхрезервиран. Ако няма място за него, не се разпределя памет и резервацията ще бъде отказана. Това е най-безопасният вариант, препоръчан за PostgreSQL. OOM-Killer се влияе от друг елемент - възможността за размяна, която се контролира от променливата cat /proc/sys/vm/swappiness
. Тези стойности казват на ядрото как да обработва пейджинг. Колкото по-висока е стойността, толкова по-малка е вероятността OOM да прекрати процеса, но поради I/O операции това има отрицателно въздействие върху базата данни. И обратното - колкото по-ниска е стойността, толкова по-голяма е вероятността от намеса на OOM-Killer, но производителността на базата данни също е по-висока. Стойността по подразбиране е 60, но ако цялата база данни се побира в паметта, по-добре е да зададете стойността на 1.
Резултати от
Не позволявайте на "убиеца" в OOM-Killer да ви плаши. В този случай убиецът ще бъде спасителят на вашата система. Той „убива“ най-лошите процеси и спасява системата от срив. За да избегнете използването на OOM-Killer за прекратяване на PostgreSQL, задайте на vm.overcommit_memory
стойност 2. Това не гарантира, че OOM-Killer няма да трябва да се намесва, но ще намали вероятността от принудително прекратяване на PostgreSQL процеса.
Източник: www.habr.com