Ответ
OOM Killer (Out-of-Memory Killer) — это механизм ядра Linux, который аварийно завершает процессы, когда система исчерпывает всю доступную память (RAM + swap), чтобы предотвратить полный крах. В продакшен-среде неправильная работа с памятью или её настройками — прямая дорога к нестабильности.
Как это работает и как диагностировать:
-
Механизм выбора «жертвы»: Ядро рассчитывает для каждого процесса
oom_score(отображается в/proc/<PID>/oom_score). Чем выше балл, тем выше вероятность быть убитым. На балл влияют:- Объем потребляемой памяти.
- Время жизни процесса (старые процессы имеют небольшой бонус).
- Значение
oom_score_adj(от -1000 до 1000), которое мы можем задать. Установка в -1000 гарантирует, что процесс никогда не будет выбран.
-
Поиск корня проблемы: OOM Killer — это симптом, а не причина. Основные действия:
- Анализ логов: Сообщение от OOM Killer попадает в
dmesgи системные логи (/var/log/kern.log).$ dmesg -T | grep -i "killed process" [Mon Mar 11 10:23:15 2024] Out of memory: Killed process 12345 (java) total-vm:20468780kB, anon-rss:15234000kB - Мониторинг: Используем инструменты вроде
htop,atop, или метрики в Prometheus (node_exporter) для отслеживания трендов использования памяти (MemAvailable,SwapUsed). Рост использования swap — ранний предупреждающий знак.
- Анализ логов: Сообщение от OOM Killer попадает в
Практические стратегии управления в DevOps:
-
Настройка через
oom_score_adj: Защищаем критически важные системные процессы (например,sshd,systemd) и, возможно, ключевые компоненты инфраструктуры.# Защищаем процесс с PID 1 (systemd) от OOM Killer echo -1000 > /proc/1/oom_score_adj # Для долгоживущего сервиса через systemd (более правильный способ) # В файле сервиса /etc/systemd/system/myservice.service добавляем: [Service] OOMScoreAdjust=-500 -
Лимитирование памяти через cgroups (основной современный подход): Это proactive, а не reactive метод. Мы явно задаем лимиты для контейнеров и сервисов.
- В Docker/Kubernetes:
# Kubernetes Pod spec resources: limits: memory: "512Mi" # Контейнер будет убит (OOMKilled), если превысит этот лимит requests: memory: "256Mi"Контейнер, превысивший
limit, будет убит немедленно (статусOOMKilled), что изолирует проблему и не затрагивает всю ноду. - На уровне системы (systemd): Можно настраивать лимиты для обычных сервисов.
[Service] MemoryMax=1G # Жесткий лимит MemoryHigh=800M # Мягкий лимит, после которого система начнет активно замедлять процесс
- В Docker/Kubernetes:
-
Настройка параметров ядра (внимательно!):
vm.overcommit_memory:0(по умолчанию): Эвристическое overcommit. Ядро разрешает выделять память, пока не наступит реальная нехватка.1: Всегда overcommit. Рискованно.2: Запрещает overcommit. Выделяется только память размеромswap + RAM * overcommit_ratio. Более безопасно, но может привести к сбоям легитимных процессов с ошибкой "Cannot allocate memory", даже если память есть.
vm.swappiness(от 0 до 100): Контролирует склонность ядра к вытеснению страниц памяти в swap. На серверах с SSD swap часто ставят1или10, чтобы использовать swap как буфер, а не ждать OOM. На серверах без swap или с очень медленным диском —0.
Итоговая философия: В современной инфраструктуре мы стараемся не полагаться на OOM Killer как на механизм стабилизации. Вместо этого мы используем лимиты cgroups (в контейнерах) и тщательный мониторинг, чтобы предсказывать и предотвращать ситуации нехватки памяти.