Налаштовуємо Out-Of-Memory Killer у Linux для PostgreSQL

Налаштовуємо Out-Of-Memory Killer у Linux для PostgreSQL

Коли Linux сервер бази даних непередбачено завершує роботу, потрібно знайти причину. Причин може бути кілька. Наприклад, SIGSEGV - Збій через бага в бекенд-сервері. Але це рідкість. Найчастіше просто закінчується простір на диску чи пам'ять. Якщо простір на диску закінчився, вихід один — звільнити місце і перезапустити базу даних.

Out-Of-Memory Killer

Коли у сервера або процесу закінчується пам'ять, Linux пропонує два шляхи вирішення: обрушити всю систему або завершити процес (додаток), який з'їдає пам'ять. Краще, звичайно, завершити процес та врятувати ОС від аварійного завершення. У двох словах, 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() вибирає процес за певними правилами.

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

Виконавши всі ці перевірки, OOM вивчає оцінку (oom_score). OOM призначає oom_score кожному процесу, та був множить це значення обсяг пам'яті. У процесів із більшими значеннями більше шансів стати жертвами OOM Killer. Процеси, пов'язані з привілейованим користувачем, мають нижчу оцінку та менше шансів на примусове завершення.

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, то коли закінчиться пам'ять, 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

Додати коментар або відгук