Выделенная память подов и вмешательство 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) и подходы как для небольшой команды с несколькими приложениями, так и для большой организации с большим количеством систем.
Настраиваем 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.
Для нее можно указывать следующие значения:
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 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, могут быть суммированы, размер заказа запроса на выделение, зона, в которой происходит