Хабрахабр

[Перевод] Настраиваем 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: Killed process 12345 (postgres).

На этом этапе ей остается только одно — завершить один или несколько процессов. Если в системе мало памяти и освободить ее невозможно, вызывается функция out_of_memory. Очевидно, что, когда вызывается out_of_memory, это связано с ожиданием операции ввода-вывода или подкачкой страницы на диск. OOM-killer должен завершать процесс сразу или можно подождать? Если все приведенные ниже проверки дадут положительный результат, OOM завершит процесс. Поэтому OOM-killer должен сначала выполнить проверки и на их основе решить, что нужно завершить процесс.

Выбор процесса

В ней есть функция select_bad_process(), которая получает оценку от функции badness(). Когда заканчивается память, вызывается функция out_of_memory(). Функция 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

Для включения и отключения используйте параметр vm.oom-kill. В Linux можно включать и отключать OOM-Killer (хотя последнее не рекомендуется). Чтобы включить 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

Значение всегда можно проверить в /proc. Еще один способ включения и отключения — написать переменную panic_on_oom.

$ 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

Мы уже говорили, что Linux может зарезервировать для процессов больше памяти, чем есть, но не выделять ее по факту, и этим поведением управляет параметр ядра Linux. OOM-Killer можно не только включать и выключать. За это отвечает переменная vm.overcommit_memory.

Для нее можно указывать следующие значения:

Это значение по умолчанию в большинстве версий Linux.
1: ядро всегда будет резервировать лишнюю память. 0: ядро само решает, стоит ли резервировать слишком много памяти. Это рискованно, ведь память может закончиться, потому что, скорее всего, однажды процессы затребуют положенное.
2: ядро не будет резервировать больше памяти, чем указано в параметре overcommit_ratio.

Если для него нет места, память не выделяется, в резервировании будет отказано. В этом параметре вы указываете процент памяти, для которого допустимо избыточное резервирование. На OOM-Killer влияет еще один элемент — возможность подкачки, которой управляет переменная cat /proc/sys/vm/swappiness. Это самый безопасный вариант, рекомендованный для PostgreSQL. Чем больше значение, тем меньше вероятности, что OOM завершит процесс, но из-за операций ввода-вывода это негативно сказывается на базе данных. Эти значения указывают ядру, как обрабатывать подкачку страниц. Значение по умолчанию 60, но если вся база данных помещается в память, лучше установить значение 1. И наоборот — чем меньше значение, тем выше вероятность вмешательства OOM-Killer, но и производительность базы данных тоже выше.

Итоги

В данном случае киллер будет спасителем вашей системы. Пусть вас не пугает «киллер» в OOM-Killer. Чтобы не приходилось использовать OOM-Killer для завершения PostgreSQL, установите для vm.overcommit_memory значение 2. Он «убивает» самые нехорошие процессы и спасает систему от аварийного завершения. Это не гарантирует, что OOM-Killer не придется вмешиваться, но снизит вероятность принудительного завершения процесса PostgreSQL.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть