Время на прочтение
5 мин
Количество просмотров 44K
Когда в 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
. На этом этапе ей остается только одно — завершить один или несколько процессов. 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 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.
Out of Memory Killer (OOM Killer) – это механизм ядра Linux, который освобождает оперативную память при ее исчерпании за счет принудительного завершения некоторых запущенных процессов.
При исчерпании памяти в системе, ядро Linux вызывает OEM killer, который по определенным правилам выбирает один процесс и убивает его. Освободившаяся память передается в распоряжение ядра, которое может предоставить ее другим процессам.
Если процесс убивается OOM Killer, в логе /var/log/messages будет такая запись:
$ cat /var/log/messages | grep "Out of"
Out of Memory: Killed process 123 (postgres) score 904 or sacrifice child
OOM killer убивает процессы сигналом SIGKILL, не предоставляя им возможность корректно завершить свое выполнение (сохранить данные, вызвать другие процессы). Поэтому результат работы OOM killer часто приводит к тяжелым последствиям.
Частое появление OOM killer говорит о нестабильности работы системы и требует от администратора внимательного анализа причин возникновения событий исчерпания памяти.
Чтобы завершить процесс, Linux вызывает функцию out_of_memory. В функции out_of_memory вызывается функция select_bad_process, которая позволяет выбрать процесс для завершения. Все запущенные процесс оцениваются с помощью функции badness. Badness выбирает процесс по правилам, основанным на вычисленной репутацим каждого процесса (oom_score).
Вы можете вывести репутацию процесса по его PID (например, для ID процесса 1764):
$ cat /proc/1764/oom_score
728
Чем выше репутация процесса, тем больше вероятность того, что именно его завершит OOM Killer.
Вы можете отключить OOM Killer в Linux (не рекомендуется в большинстве случаев):
$ sudo cat /proc/sys/vm/panic_on_oom
По умолчанию тут указан 0. Это значит, что OOM Killer включен.
Чтобы отключить его:
$ sudo echo 1 > /proc/sys/vm/panic_on_oom
Если вы не хотите отключать OOM Killer, но хотите гарантировать, что определенный процесс никогда не будет принудительно завершен, нужно увеличить его репутацию.
Выведите текущую репутацию процесса:
$ cat /proc/1764/oom_score
Можно увеличить, или уменьшить репутацию процесса, добавив в файл oom_adj значение от -16 до +15.
Например, так:
$ sudo echo -5 > /proc/1764/oom_adj
$ cat /proc/1764/oom_score
Если нужно совсем отключить OOM Killer для процесса, нужно указать в oom_adj значение -17.
$ sudo echo -17 > /proc/1764/oom_adj
$ cat /proc/1764/oom_score
Однако нужно понимать, что при перезапуске процесса, его PID изменится. И эта репутация будет переназначена другому процессу с таким же PID.
Можно динамически определять PID процесса и уменьшать его репутацию:
$ pgrep -f "/usr/sbin/sshd" | while read PID; do echo -17 > /proc/$PID/oom_adj; done
Но гораздо удобнее задать репутацию в файле сервиса юнита службы systemd:
[Service] OOMScoreAdjust=-500
На чтение 3 мин Опубликовано 25.10.2018
Содержание
- Что такое OOM Killer?
- Отключение OOM-KILLER в CentOS / RHEL
- Заключение
Что такое OOM Killer?
Убийца OOM, включенный по умолчанию, является механизмом самозащиты, использующим ядро Linux при сильном использовании памяти.
Если ядро не может найти память для выделения, когда это необходимо, она помещает страницы пользовательских данных в очередь подкачки.
Если виртуальная память (VM) не может выделять память и не может поменять ее в используемой памяти, киллер может начать убивать текущие процессы из памяти в пользовательском пространстве. он пожертвует одним или несколькими процессами, чтобы освободить память для системы, когда все остальное не удастся.
Если у вас есть строка, как показано ниже в / var / log / messages:
Apr 1 00:01:02 srv01 kernel: Out of Memory: Killed process 2592 (oracle).
это означает, что киллер OOM убил серверный процесс 2592 Oracle.
Отключение OOM-KILLER в CentOS / RHEL
В Red Hat Enterprise Linux 5 и 6 нет возможности полностью отключить OOM-KILLER. См. Следующий раздел для настройки работы OOM-KILLER в RHEL 5 и RHEL 6.
Можно определить, какие процессы будут убиты путем корректировки оценки oom_killer.
В / proc / PID / есть два инструмента с метками oom_adj и oom_score.
Действительные оценки для oom_adj находятся в диапазоне от -16 до +15.
Это значение используется для вычисления «плохого» процесса с использованием алгоритма, который также учитывает, как долго процесс был запущен, среди других факторов.
Чтобы увидеть текущий счет oom_killer, просмотрите oom_score для процесса.
oom_killer сначала уничтожит процессы с наивысшими баллами.
В этом примере настраивается oom_score процесса с помощью PID 12465, чтобы уменьшить вероятность того, что oom_killer убьет его.
# cat /proc/12465/oom_score 79872 # echo -5 > /proc/12465/oom_adj # cat /proc/12465/oom_score 78
Существует также специальное значение -17, которое отключает oom_killer для этого процесса.
В приведенном ниже примере oom_score возвращает значение 0, указывая, что этот процесс не будет убит.
# cat /proc/12465/oom_score 78 # echo -17 > /proc/12465/oom_adj # cat /proc/12465/oom_score 0
Установка «overcommit_memory» на 2, позволяет вам быть точным в отношении избыточной памяти.
Оно указывает, что ядро никогда не будет выполнять адресное пространство, большее, чем пространство подкачки, и фракцию «overcommit_ratio» физической памяти.
Commit = swap + (overcommit_ratio/100) * physical memory
Когда использование памяти попадает в этот номер, больше не должно быть никаких ассигнований.
Committed_AS в / proc / meminfo показывает текущий объем памяти в системе.
Заключение
Out of Memory (OOM) относится к вычислительному состоянию, в котором выделена вся доступная память, включая пространство подкачки.
Обычно это приведет к panic error и остановке системы.
Хотя OOM нельзя полностью отключить в CentOS / RHEL 5,6; он может быть настроен на то, чтобы определить, какие процессы будут убиты, отрегулировав счет oom_killer.
Пожалуйста, не спамьте и никого не оскорбляйте.
Это поле для комментариев, а не спамбокс.
Рекламные ссылки не индексируются!
OOM Killer, пожалуй, одна из немногих технологий в Linux, овеянная мифами и легендами. Часто из уст в уста передаются истории, претендующие на хороший триллер. На самом деле все гораздо проще и прозаичнее, а работа OOM Killer подчиняется строгим правилам. Cегодня мы попробуем разобраться в том, что такое OOM Killer и для чего он предназначен, а также разберемся как он работает и по каким критериям выбирает процессы для завершения. Поэтому, если OOM Killer для вас все еще мифический и непонятный черный ящик, то обязательно прочитайте эту статью.
Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном курсе по администрированию MikroTik. Автор курса, сертифицированный тренер MikroTik Дмитрий Скоромнов, лично проверяет лабораторные работы и контролирует прогресс каждого своего студента. В три раза больше информации, чем в вендорской программе MTCNA, более 20 часов практики и доступ навсегда.
Начнем с начала, т.е. с выделения памяти в Linux. Любой запущенный процесс получает собственный выделенный участок памяти. Но этот участок не отображается на доступные физические адреса, а использует виртуальное адресное пространство, которое является дополнительным слоем абстракции между процессом и физической памятью. Для сопоставления адресов между виртуальной и физической памятью используются специальные структуры — таблицы страниц.
Что это дает? Во-первых, изоляцию процессов друг от друга, каждый из них работает в собственном виртуальном адресном пространстве и не имеет доступа к памяти других процессов. Во-вторых, позволяет системе гибко управлять физической памятью, например, для неактивного процесса часть страниц может быть перенесено из оперативной памяти в пространства подкачки, но это никак не повлияет на работу самого процесса, его адресное пространство не изменится, поменяется лишь трансляция в таблице страниц. И, наконец, это позволяет экономить физическую память, так если несколько процессов используют одни и те же данные, то система может транслировать адреса виртуальных пространств на один и тот же участок физической памяти.
Таким образом размер виртуальной памяти в системе теоретически ничем не ограничен и общий ее объем может существенно превышать имеющуюся в наличии физическую память. И в этом нет ничего плохого, например, мы запустили несколько графических приложений, для работы которым требуются библиотеки Qt или GTK, но нужно ли каждый раз загружать их в память? Нет, достаточно сделать это один раз, а затем просто транслировать адреса виртуальной памяти процессов на одни и те же участки физической памяти. Но при этом каждый процесс будет думать, что у него загружена собственная копия библиотек.
Поэтому современные Linux-системы выделяют память процессам с превышением имеющейся в наличии физической памяти (RAM + Swap), по умолчанию используя эвристические механизмы. Но случается, что процессы съедают всю доступную физическую память и вот тут системе надо выбрать что-то одно. А выбор, скажем честно, между плохим или очень плохим. Можно убить один из процессов и продолжить работать дальше, а можно вызвать Kernel panic. Понятно, что последнее — это совсем ни в какие ворота, поэтому на сцену выходит OOM Killer, это поведение используется в современных Linux системах по умолчанию.
Но кого же убьет OOM Killer? Бытует ошибочное мнение, что самый «толстый» процесс, занимающий самое большое количество памяти, однако это не так. Хотя заблуждения живучи, и народная молва рисует OOM Killer в виде ковбоя, врывающегося в переполненный салун и открывающий беспорядочную стрельбу по посетителям, преимущественно по толстым. Почему? Да попасть, наверное, проще…
На самом деле OOM Killer использует достаточно сложный анализ и присваивает каждому процессу очки негодности (badness) и при исчерпании памяти будет убит не кто-попало, а самый негодный процесс. Очки негодности могут принимать значения от -1000 до 1000, чем выше значение, тем более высока вероятность что OOM Killer убьет процесс. Процесс с -1000 очков никогда не будет убит OOM Killer.
Как вычисляются очки негодности? За основу берется процент физической памяти используемый процессом и умножается на 10, таким образом получаем базовое значение. Нетрудно заметить, что 1000 очков — это 100% использования памяти. Затем к данному значению начинают применяться различные модификаторы:
- Прибавляется половина очков всех дочерних процессов, имеющих собственную виртуальную память.
- Если приоритет процесса больше нуля очки умножаются на два. Приоритет может иметь значение от -20 (наивысший приоритет) до 20 (самый низкий).
- Очки делятся на коэффициент, связанный с процессорным временем, чем более активен процесс и чем больше процессорного времени он использует, тем больше будет этот коэффициент.
- Очки делятся на коэффициент, связанный с временем жизни процесса, чем больше времени прошло с момента запуска, тем выше будет это значение.
- Для процессов, запущенных от имени root, обслуживающих систему или процессов ввода-вывода очки делятся на 4.
- Для процесса, при выделении памяти которому произошла ошибка out of memory и процессам имеющим с ним общую память, очки делятся на 8.
- Очки умножаются на 2^oom_adj, где oom_adj — специальный коэффициент, имеющий значения от -17 до 15, при -17 процесс никогда не будет убить OOM Killer.
Если внимательно изучить эти критерии, то становится ясно, что OOM Killer убьет самый «толстый» процесс, который наименее активен в системе и имеет самое короткое время жизни. Согласитесь, это не тоже самое, что убить процесс с самым большим потреблением памяти. Такой подход позволяет достаточно эффективно бороться с утечкой памяти в кривых приложениях, минимизируя их влияние на систему.
Не так давно нам пришлось разбираться с ситуацией: в Linux Mint начал подвисать и падать браузер Chrome. Анализ ситуации выявил, что пользователь поставил стороннее расширение, которое приводило к утечке памяти и зависанию браузера, после чего на сцену выходил OOM Killer и убивал процесс. При этом параллельно были открыты процессы, которые потребляли больше памяти, чем утекало через Chrome, но OOM Killer их не трогал.
В системах виртуализации это будет неактивная виртуалка с наибольшим выделением памяти. Поэтому если у вас регулярно выключается одна из второстепенных машин — проверьте ситуацию с памятью, скорее всего это работа OOM Killer.
Как узнать количество очков, присвоенных процессу? Довольно просто, выполните команду:
cat /proc/PID/oom_score
Где PID — идентификатор процесса. При необходимости мы можем изменить количество очков используя коэффициент oom_adj:
echo -17 > /proc/PID/oom_adj
В данном случае мы отправили процессу с указанным PID значение -17, т.е. обеспечили ему полную защиту от OOM Killer.
Все это имеет один большой недостаток: применить коэффициент oom_adj мы можем только к запущенному процессу и по факту это ручная работа. Не следует применять эти методы на практике, кроме, разве что диагностики и отладки.
В современных системах для управления службами используется systemd, который дает нам в руки простые и эффективные инструменты для управления очками негодности. Для этого в секцию [Service] юнита службы добавьте опцию:
[Service]
...
OOMScoreAdjust=-500
...
Значение OOMScoreAdjust показывает насколько следует изменить количество очков процесса относительно рассчитанного количества, в нашем примере мы уменьшили его на 500. Таким образом мы можем защитить важные службы вашей системы от убийства со стороны OOM Killer, но не стоит злоупотреблять этой опцией, в критической ситуации будет лучше, если OOM Killer убьет даже важный процесс, но сохранит вам доступ к системе, нежели вы окажетесь в ситуации с полным исчерпанием физической памяти и недоступности или перезагрузки вашего сервера.
В любом случае, если вы столкнулись с работой OOM Killer, то следует тщательно проанализировать причины нехватки физической памяти и принять необходимые меры.
Надеемся, что после прочтения данной статьи OOM Killer перестанет быть для вас мифическим персонажем и вы будете понимать, что именно он делает, зачем и исходя из каких соображений. После чего он перестанет быть непредсказуемым черным ящиком, а станет вашим другом, помогающим сохранить работоспособность системы в критической ситуации нехватки ресурсов.
Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном курсе по администрированию MikroTik. Автор курса, сертифицированный тренер MikroTik Дмитрий Скоромнов, лично проверяет лабораторные работы и контролирует прогресс каждого своего студента. В три раза больше информации, чем в вендорской программе MTCNA, более 20 часов практики и доступ навсегда.
На Linux-системах с небольшим объемом физической оперативной памяти (например, на VPS-ках) часто можно заметить, что какой-либо процесс внезапно прекращает работу. В чем же дело? Оказывается, он «убит», а виновник — злобный OOM Killer !
OOM Killer представляет собой компонент ядра Linux, защитный механизм, призванный решать проблемы с нехваткой физической памяти (OOM — Out of memory). При обнаружении недостатка памяти OOM Killer «убивает» наименее важный по его мнению процесс, посылая ему сигнал KILL (исключения составляют лишь init и ядерные нити (kernel threads)). Сообщение о об этом появляется в журнале /var/log/syslog в виде:
Out of memory: Kill process **** (****) score **** or sacrifice child
Killed process **** (****)
Но мнение пользователя системы не всегда совпадает с мнением «киллера» 🙂 Как же быть? Как заставить OOM Killer не трогать дорогие нашему сердцу процессы?
На моей VPS-ке жертвой OOM Killer часто становится FTP-сервер ProFTPD. Прекратим это хулиганство! 🙂
Сначала выясним идентификатор (PID) процесса FTP-сервера — proftpd:
Идентификатор оказывается равным 3234.
Затем настроим OOM Killer так, чтобы он даже и не думал убить процесс с PID 3234 — записывает в файл oom_adj в соответствуюшем каталоге (/proc/PID/oom_adj)
магическое число -17 (OOM score):
Проверим заданные настройки:
-17 — всё в порядке! Voi la! Теперь мой FTP-сервер вечно живой 🙂