oom killer что это
Настраиваем Out-Of-Memory Killer в Linux для PostgreSQL
Когда в Linux сервер базы данных непредвиденно завершает работу, нужно найти причину. Причин может быть несколько. Например, SIGSEGV — сбой из-за бага в бэкенд-сервере. Но это редкость. Чаще всего просто заканчивается пространство на диске или память. Если закончилось пространство на диске, выход один — освободить место и перезапустить базу данных.
Out-Of-Memory Killer
Когда у сервера или процесса заканчивается память, Linux предлагает 2 пути решения: обрушить всю систему или завершить процесс (приложение), который съедает память. Лучше, конечно, завершить процесс и спасти ОС от аварийного завершения. В двух словах, Out-Of-Memory Killer — это процесс, который завершает приложение, чтобы спасти ядро от сбоя. Он жертвует приложением, чтобы сохранить работу ОС. Давайте сначала обсудим, как работает OOM и как его контролировать, а потом посмотрим, как OOM Killer решает, какое приложение завершить.
Одна из главных задач Linux — выделять память процессам, когда они ее просят. Обычно процесс или приложение запрашивают у ОС память, а сами используют ее не полностью. Если ОС будет выдавать память всем, кто ее просит, но не планирует использовать, очень скоро память закончится, и система откажет. Чтобы этого избежать, ОС резервирует память за процессом, но фактически не выдает ее. Память выделяется, только когда процесс действительно собирается ее использовать. Случается, что у ОС нет свободной памяти, но она закрепляет память за процессом, и когда процессу она нужна, ОС выделяет ее, если может. Минус в том, что иногда ОС резервирует память, но в нужный момент свободной памяти нет, и происходит сбой системы. OOM играет важную роль в этом сценарии и завершает процессы, чтобы уберечь ядро от паники. Когда принудительно завершается процесс PostgreSQL, в логе появляется сообщение:
Выбор процесса
Выполнив все эти проверки, OOM изучает оценку ( oom_score ). OOM назначает oom_score каждому процессу, а потом умножает это значение на объем памяти. У процессов с большими значениями больше шансов стать жертвами OOM Killer. Процессы, связанные с привилегированным пользователем, имеют более низкую оценку и меньше шансов на принудительное завершение.
Идентификатор процесса Postgres — 3813, поэтому в другой оболочке можно получить оценку, используя этот параметр ядра oom_score :
Принудительное завершение процесса
Как контролировать OOM-Killer
Чтобы отключить OOM-Killer, укажите значение 0 в этой же команде:
Результат этой команды сохранится не навсегда, а только до первой перезагрузки. Если нужно больше постоянства, добавьте эту строку в файл /etc/sysctl.conf :
Если установить значение 0, то когда закончится память, kernel panic не будет.
Если установить значение 1, то когда закончится память, случится kernel panic.
Для нее можно указывать следующие значения:
Выделенная память подов и вмешательство OOM Killer
И снова здравствуйте! Перевод следующей статьи подготовлен специально для студентов курса «Инфраструктурная платформа на основе Kubernetes», который запускается уже в этом месяце Начнем.
В последние дни некоторые из моих подов постоянно аварийно завершали работу, оставляя в системном журнале ОС запись о том, что OOM Killer уничтожил процесс контейнера. Я решил разобраться, почему это происходит.
Лимит памяти подов и параметры памяти cgroup
Проведем тест на дистрибутиве K3s. Создаем под с характерным лимитом памяти — 123 МиБ (123 Mi).
В другой консоли выясняем uid пода.
128974848 — это ровно 123 МиБ (123*1024*1024). Ситуация проясняется. Выходит, в Kubernetes лимит памяти задается через cgroup. Как только под разрастется больше отведенного лимита памяти, cgroup инициирует уничтожение процесса контейнера.
Стресс-тест
Давайте установим утилиты для стресс-тестирования пода через открытый сеанс командной консоли.
Сначала запустим утилиту стресс-тестирования, выделив ей в памяти 100 МБ. Процесс запустился успешно.
Теперь проведем второй стресс-тест.
Запуск привел к мгновенному уничтожению процесса первого стресс-теста (PID 271) по сигналу 9.
Тем временем в системном журнале появились такие записи:
Процесс с PID 32308 на хосте уничтожен в связи с нехваткой памяти (OOM). Но самое интересное скрывается в конце журнальных записей:
Выясняем объем памяти, доступной узлу:
Итак, все процессы в контейнере обладают одинаковым значением oom_score_adj. Компонент OOM Killer рассчитывает значение OOM, исходя из использования памяти, и корректирует результат с учетом оценки oom_score_adj. И, в конечном счете, он уничтожает процесс первого стресс-теста, который отъел большую часть памяти, 100 МБ, что соответствует оценке oom_score = 1718.
Заключение
Kubernetes контролирует лимит памяти подов через параметры cgroup и компонент OOM Killer. Необходимо внимательно согласовывать условия OOM операционной системы и OOM подов.
Как вам материал? Всех, кто желает подробнее узнать о курсе, приглашаем 17 июня на бесплатный вебинар, где изучим возможности Kubernetes для организации практики непрерывной поставки (CI/CD) и подходы как для небольшой команды с несколькими приложениями, так и для большой организации с большим количеством систем.
OOMkiller в Docker сложнее, чем вы думаете
Снова здравствуйте. В преддверии старта курса «Разработчик Java» подготовили перевод еще одного небольшого материала.
Недавно у одного из пользователей Plumbr APM возникла странная проблема с аварийной остановкой docker-контейнера с кодом 137. Конфигурация была простейшая с несколькими вложенными контейнерами и виртуальными машинами, похожая на матрешку:
Смотрим syslog и видим, что, действительно, был вызван oomkiller:
Как видно, java-процесс достиг лимита в 3145728 кБ (это около 3ГБ), что и вызвало остановку контейнера. Это довольно странно, так как сам docker был запущен с ограничением в 4 ГБ (в файле docker-compose ).
Пока мы не понимаем, что происходит. Docker должен разрешить использовать 4 ГБ. Так почему же OOMkiller сработал на 3 ГБ? Дальнейший поиск информации привел нас к тому, что есть еще одно ограничение памяти в ОС, которая была развернута на железе.
Скажите спасибо cgroups (control groups, контрольные группы). cgroups — это механизм ядра Linux для ограничения, контроля и учета использования ресурсов группами процессов. По сравнению с другими решениями (команда nice или /etc/security/limits.conf ), cgroups предоставляют большую гибкость, так как они могут работать с (под)наборами процессов.
В нашей ситуации cgroups ограничивали использование памяти в 3 ГБ (через memory.limit_in_bytes ). У нас определённый прогресс!
Исследование памяти и событий GC с помощью Plumbr показало, что большую часть времени JVM использовало около 700 МБ. Исключение было только непосредственно перед остановкой, когда происходил всплеск выделения памяти. За ним следовала длительная пауза GC. Итак, кажется, происходило следующее:
Выводы
Даже в такой простой ситуации, было три ограничения памяти:
Еще один вывод для разработчиков docker. Кажется, нет смысла разрешать запускать такие «матрешки», в которых ограничение памяти вложенного контейнера выше, чем ограничение cgroups. Простая проверка этого при запуске контейнера с отображением соответствующего предупреждения может сэкономить сотни часов отладки для ваших пользователей.
Что убило мой процесс и почему?
Мое приложение работает в Linux как фоновый процесс. В настоящее время он запускается из командной строки в окне терминала.
Недавно пользователь некоторое время исполнял приложение, и оно загадочным образом умерло. Текст:
был на терминале. Это случилось два раза. Я спросил, использует ли кто-то в другом Терминале команду kill, чтобы завершить процесс? Нет.
Если пользователь или системный администратор не убили программу, возможно, ядро. Ядро будет убивать процесс только в исключительных обстоятельствах, таких как чрезвычайное истощение ресурсов (например, mem + swap исчерпание).
Опустить -T в Mac OS.
Суть в том, что Linux overcommits memory. Когда процесс запрашивает больше места, Linux предоставит ему это пространство, даже если это запрашивается другим процессом, исходя из предположения, что никто фактически не использует всю запрашиваемую память. Процесс получит исключительное использование памяти, которую он выделил, когда он фактически использует ее, а не когда он запрашивает ее. Это делает распределение быстрым и может позволить вам «обмануть» и выделить больше памяти, чем у вас есть на самом деле. Однако, как только процессы начнут использовать эту память, Linux может осознать, что она слишком щедра в распределении памяти, которой у нее нет, и ей придется завершить процесс, чтобы освободить его. Уничтожаемый процесс основан на оценке, учитывающей время выполнения (длительные процессы безопаснее), использование памяти (жадные процессы менее безопасны) и некоторые другие факторы, включая значение, которое можно настроить, чтобы сделать процесс менее быстрым. может быть убит. Все это описано в статье более подробно.
Позвольте мне сначала объяснить, когда и почему вызывается OOMKiller?
Допустим, у вас есть 512 RAM + 1 ГБ подкачки памяти. Таким образом, теоретически ваш процессор имеет доступ к 1,5 ГБ виртуальной памяти.
В течение некоторого времени все работает нормально в пределах 1,5 ГБ общей памяти. Но внезапно (или постепенно) ваша система начала потреблять все больше и больше памяти, и она достигла примерно 95% от общего объема используемой памяти.
Теперь скажите, что любой процесс запросил большой кусок памяти у ядра. Ядро проверит доступную память и обнаружит, что нет способа выделить вашему процессу больше памяти. Поэтому он попытается освободить память, вызывающую/вызывающую OOMKiller ( http://linux-mm.org/OOM ).
Где я могу найти логи OOMKiller?
Обычно в каталоге/var/log. Либо /var/log/kern.log или/var/log/dmesg
Надеюсь, что это поможет вам.
Некоторые типичные решения:
Вы увидите сообщение вроде:
Как заявили dwc и Адам Яскевич, виновник, скорее всего, убийца ООМ. Тем не менее, следующий вопрос, который следует: как я могу предотвратить это?
Есть несколько способов:
Модуль PAM для ограничения ресурсов вызвал именно те результаты, которые вы описали: мой процесс загадочно прервался с текстом Killed в окне консоли. Нет вывода журнала, ни в syslog, ни в kern.log. Программа top помогла мне обнаружить, что ровно после одной минуты использования процессора мой процесс прерывается.
Такой инструмент, как systemtap (или трассировщик), может контролировать логику передачи сигналов ядра и создавать отчеты. например, https://sourceware.org/systemtap/examples/process/sigmon.stp
Блок фильтрации if в этом скрипте может быть настроен по вкусу или исключен для отслеживания общесистемного сигнального трафика. Причины могут быть дополнительно изолированы путем сбора обратных следов (добавьте print_backtrace() и/или print_ubacktrace() к зонду для ядра и пользовательского пространства соответственно).
В среде lsf (интерактивной или иной), если приложение превышает использование памяти сверх некоторого заданного порога администраторами в очереди или запросом ресурсов при отправке в очередь, процессы будут убиты, так что другие пользователи не станут жертвами потенциального убегай. Он не всегда отправляет электронное письмо, когда это делает, в зависимости от того, как он настроен.
Одним из решений в этом случае является поиск очереди с большими ресурсами или определение больших требований к ресурсам в представлении.
Вы также можете рассмотреть man ulimit
У нас периодически возникали проблемы под Linux на сайте заказчика (я думаю, в Red Hat), когда OOMKiller (убийца нехватки памяти) убивал как наше основное приложение (т. Е. Причину существования сервера), так и процессы базы данных.
Русские Блоги
Введение в механизм Linux OOM killer
Описание концепции
2. Причины убийцы ООМ
2.1 выделение памяти malloc
By default, Linux follows an optimistic memory allocation strategy.
This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. This is a really bad bug. In case it turns out that the system is out of memory, one or more processes will be killed by the infamous OOM killer.
Вышеприведенный фрагмент является выдержкой из man-страницы malloc, указывающей, что malloc возвращает ненулевой указатель, не означает, что указание на память доступно, а когда система не имеет памяти, она освобождает память, убивая процесс.
2.2 Memory Overcommit
3. Распределение виртуальной памяти
3.1 Влияющие на параметры
3.1.1 overcommit_memory
Используется для управления переключателем политики overcommit ядра.
Необязательное значение | смысл |
---|---|
OVERCOMMIT_GUESS(0) | Разрешить overcommit по мере необходимости. Когда система выделяет виртуальное адресное пространство для процесса приложения, она определяет, превышает ли текущий примененный размер виртуального адресного пространства оставшийся объем памяти. Если он превышает, распределение виртуального адресного пространства завершается неудачно. |
OVERCOMMIT_ALWAYS(1) | Overcommit всегда разрешен. Когда система выделяет виртуальное адресное пространство для процесса приложения, она вообще не ограничивает его, избегая возможного отказа fork, а потому, что malloc сначала выделяет виртуальное адресное пространство, а затем перехватывает ядро для выделения реальной физической памяти через исключение. В последующем восприятие процесса приложения состояния системной памяти полностью экранировано, то есть malloc всегда может быть успешным, но если памяти недостаточно, это вызывает процесс уничтожения OOM системы. |
OVERCOMMIT_NEVER(2) | Отключить overcommit. Определите верхний предел виртуального адресного пространства на основе состояния системной памяти. Однако во многих случаях виртуальное адресное пространство процесса занимает намного больше, чем физическая память, которую он фактически занимает, поэтому, как только использование памяти увеличится, легко создать сбой для некоторых динамически генерируемых процессов (необходимо скопировать адресное пространство родительского процесса). Процесс не имеет слишком много такого динамического применения памяти или создания дочерних процессов, воздействие невелико, иначе это будет иметь относительно большое влияние |
3.1.2 overcommit_ratio
3.1.3 admin_reserve_kbytes
Объем свободной памяти, зарезервированный системой для пользователей с разрешениями cap_sys_admin. По умолчанию используется 3% свободных страниц и меньше 8 МБ, что позволяет администраторам входить в систему и завершать процессы.
3.1.4 user_reserve_kbytes
Объем свободной памяти, зарезервированный системой для обычных пользователей, вступает в силу только в том случае, если отключена избыточная загрузка. Значение по умолчанию составляет 3% свободных страниц и меньше 128 МБ, так что пользователи могут входить в систему и завершать процессы.
3.1.5 CommitLimit и Commited_AS
Информация / proc / meminfo, которая вступает в силу, когда запрещен чрезмерный коммит.
3.2 Память достаточно суждения
Когда пользовательское пространство выделяет память, ядро вызывает __vm_enough_memory () (mm / mmap.c), чтобы убедиться, что виртуальной памяти достаточно для выделения.
4. Распределение физической памяти
4.1 Влияющие на параметры
4.1.1 min_free_kbytes
4.1.2 lowmem_reserve_ratio
Результаты расчета можно просмотреть с помощью следующей команды.
4.2 Память достаточно суждения
Перед выполнением алгоритма партнерской системы для выделения фреймов страницы необходимо вызвать zone_watermark_ok () (mm / page_alloc.c), чтобы определить, соответствует ли количество фреймов страницы в текущей области памяти требованиям к водяному знаку. Если требования не будут выполнены, распределение будет неудачным, что в конечном итоге приведет к OOM.
Проще говоря, до тех пор, пока количество оставшихся страниц превышает уровень воды после выделения, вы можете безопасно вернуться. Но партнерская система учитывает не только оставшееся, но и общее количество, но также и ситуацию фрагментации памяти.Приведенный выше цикл проверки фактически гарантирует, что страницы верхнего и нижнего порядка будут примерно сбалансированы. Особенно, когда есть несколько free_pages, которые находятся рядом с водяным знаком.
4.3 Факторы, влияющие на ООМ
В соответствии с вышеприведенным описанием факторы, влияющие на возникновение OOM, могут быть суммированы, размер заказа запроса на выделение, зона, в которой происходит запрос на выделение, размер водяного знака зоны и степень фрагментации памяти.
5. Параметры отладки OOM killer
5.1 panic_on_oom
Он используется для управления включением панического переключателя при запуске OOM ядра.
Необязательное значение | смысл |
---|---|
0 | Не вызывает паники. |
1 | Если он не выделен для памяти из-за таких ограничений, как policy, cpuset, memcg и т. Д., То паника не запускается, в противном случае запускается паника. |
2 | Вызвать панику напрямую. |
5.2 oom_dump_tasks
Используется для контроля того, вызывает ли ядро OOM функцию dump_tasks для печати состояния памяти всех задач.
Необязательное значение | смысл |
---|---|
0 | Печать не вызывается (печать по одному может вызвать проблемы с производительностью при наличии большого количества процессов). |
1 | Печать будет выполняться в следующих ситуациях: а) паника ядра из-за OOM, б) неспособность найти подходящий плохой процесс, в) когда найден подходящий процесс для уничтожения. |
5.3 oom_kill_allocating_task
Он используется для контроля того, будет ли процесс, который запускает OOM, преимущественно уничтожаться при выполнении OOM ядра.
5.4 oom_score_adj
Параметры оценки процесса, уникальные для каждого процесса.