Что означает ошибка OOM
OOM (Out Of Memory) Killer — это встроенный механизм ядра Linux, который срабатывает, когда система полностью исчерпывает оперативную память (RAM) и пространство подкачки (swap). Вместо того чтобы позволить серверу зависнуть намертво, ядро выбирает и принудительно завершает один или несколько процессов, освобождая ресурсы.
В логах это обычно выглядит как строка: Out of memory: Kill process <PID> (<имя_процесса>) score <число> or sacrifice child. Процесс не просто падает — его убивает сигнал SIGKILL (9), который невозможно перехватить. Поэтому в логах самого приложения вы не увидите стандартных сообщений об ошибках, только внезапную остановку.
Причины возникновения
- Утечка памяти (Memory Leak): Приложение постепенно захватывает всё больше RAM и не освобождает её. Со временем свободной памяти не остаётся.
- Некорректная конфигурация сервера: Под веб-сервер или БД выделено слишком мало ресурсов, либо в конфигурационных файлах заданы завышенные лимиты на воркеры или буферы.
- Отсутствие или малый объём Swap: Если физическая память заканчивается, а область подкачки не настроена, ядро мгновенно запускает OOM Killer без попытки использовать диск.
- Внезапный всплеск нагрузки: Резкий наплыв трафика, запуск тяжёлых скриптов или компиляция программ (например,
npm installилиmake) на слабом VPS.
Способы решения
Способ 1: Анализ логов и выявление жертвы
Прежде чем менять настройки, убедитесь, что виновником действительно является OOM Killer, и узнайте, какой процесс пострадал.
- Откройте терминал и выполните команду для просмотра сообщений ядра:
sudo dmesg -T | grep -i "out of memory"
- Если вывод пустой, проверьте системный журнал:
journalctl -k | grep -i oom
- Найдите строки с
Killed process [PID] (process_name). Обратите внимание на значениеoom_score— чем оно выше, тем больше шансов, что процесс будет убит в следующий раз.
💡 Совет: Если процесс убивается регулярно, добавьте мониторинг памяти (например,
htopилиfree -m), чтобы отследить момент скачка потребления.
Способ 2: Настройка приоритетов через oom_score_adj
Ядро Linux оценивает каждый процесс по шкале от -1000 до 1000. Значение -1000 полностью защищает процесс от OOM Killer, а 1000 делает его первой жертвой. По умолчанию значение равно 0.
- Узнайте PID критичного процесса (например, вашей БД):
pidof mysqld
- Измените его приоритет, записав новое значение в специальный файл:
echo -500 | sudo tee /proc/<PID>/oom_score_adj
- Чтобы настройка сохранялась после перезагрузки, добавьте правило в
systemdдля вашего сервиса. Откройте оверрайд конфигурации:
sudo systemctl edit mysqld.service
- Вставьте следующие строки и сохраните файл:
[Service]
OOMScoreAdjust=-500
- Перезагрузите конфигурацию демона:
sudo systemctl daemon-reload.
Способ 3: Оптимизация Swap и параметров ядра
Если сервер регулярно упирается в лимиты RAM, добавление области подкачки даст ядру больше времени на реакцию и снизит частоту срабатываний OOM Killer.
- Создайте файл подкачки размером 2 ГБ:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
- Добавьте его в
/etc/fstab, чтобы он активировался при загрузке:
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
- Настройте агрессивность использования swap через параметр
vm.swappiness. Значение10означает, что система будет активно использовать RAM, и обращаться к диску только при острой необходимости:
sudo sysctl vm.swappiness=10
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
⚠️ Важно: Не отключайте OOM Killer полностью через
vm.panic_on_oom=1. Это заставит ядро перезагружать сервер при нехватке памяти, что приведёт к простою и возможной потере данных.
Способ 4: Ограничение потребления через cgroups или systemd
Лучший способ предотвратить срабатывание OOM Killer — заранее задать жёсткие лимиты для сервисов. systemd позволяет сделать это без сложных настроек cgroups вручную.
- Откройте конфигурацию сервиса, который потребляет слишком много памяти:
sudo systemctl edit apache2.service
- Добавьте директивы ограничения памяти:
[Service]
MemoryMax=1G
MemorySwapMax=500M
Это не даст процессу превысить 1 ГБ ОЗУ и 500 МБ подкачки. При достижении лимита сервис будет корректно остановлен или перезагружен, а не убьёт соседние процессы.
3. Примените изменения: sudo systemctl restart apache2.
Профилактика
Регулярно обновляйте пакеты сервера и приложения: разработчики часто исправляют утечки памяти в новых версиях. Настройте автоматический перезапуск сервисов при сбоях (Restart=always в юнитах systemd), чтобы критичные приложения поднимались сразу после аварийной остановки. Используйте мониторинг (Prometheus, Netdata или Zabbix) с алертами при достижении 85% использования RAM. Это даст вам запас времени для ручного вмешательства до того, как ядро Linux начнёт самостоятельно "чистить" процессы.