PHP-FPM Ошибка: child exited on signal 9 (SIGKILL - OOM Killer)
Механизм принудительного уничтожения процессов Out-of-Memory (OOM) Killer
Системный сигнал Signal 9 (SIGKILL) — это безусловная команда ядра операционной системы на немедленное уничтожение процесса без возможности перехвата или обработки завершения. Запись в системном журнале PHP-FPM «WARNING: [pool www] child exited on signal 9 (SIGKILL)» в 99% случаев свидетельствует о том, что на сервере полностью исчерпана физическая оперативная память (RAM) и пространство подкачки (Swap). В критический момент активизируется механизм ядра Linux OOM-Killer (Out of Memory Killer), который подсчитывает показатель штрафа oom_score для всех процессов и принудительно убивает воркер PHP-FPM, потребивший больше всего памяти, спасая операционную систему от полного зависания.
Бизнес-риски
Аварийный обрыв генерации тяжелых финансовых отчетов, сбой экспорта каталогов в маркетплейсы, появление ошибок 502 Bad Gateway у пользователей во время выполнения запроса.
Сравнение превышения memory_limit в PHP и уничтожения OOM-Killer ядра
| Параметр | Превышение PHP memory_limit | Уничтожение Linux OOM-Killer (Signal 9) |
|---|---|---|
| Кто инициирует | Виртуальная машина PHP (Zend Engine). | Ядро операционной системы Linux. |
| Сообщение в логе | Allowed memory size of X bytes exhausted | child exited on signal 9 (SIGKILL) |
| Логирование | Пишется в стандартный php_error.log. | Пишется в системный буфер ядра dmesg / syslog. |
| Штатное завершение | PHP корректно закрывает соединения и отдает HTTP 500. | Процесс уничтожается мгновенно, веб-сервер возвращает HTTP 502. |
Регламент диагностики и устранения инцидентов OOM-Killer
Шаг 1: Подтверждение факта работы OOM-Killer через системные журналы ядра
# 1. Поиск записей OOM-Killer в кольцевом буфере ядра dmesg:
sudo dmesg -T | grep -i -E "oom[-_]killer|killed process"
# Пример вывода:
# [Mon Mar 10 14:22:01 2025] Out of memory: Killed process 15842 (php-fpm8.2) total-vm:2048500kB, anon-rss:1540200kB, file-rss:0kB
# 2. Проверка истории в системном логе syslog / journalctl:
sudo journalctl -k --since "2 hours ago" | grep -i oomШаг 2: Ограничение потребления памяти в php.ini
Установите жесткий лимит памяти на уровне одного запроса, чтобы PHP перехватывал превышение до того, как сработает OOM-Killer ядра:
# 1. Отредактируйте php.ini для FPM:
sudo nano /etc/php/8.2/fpm/php.ini
# Задайте адекватный лимит (например, 256M или 512M вместо -1 или 4G!):
memory_limit = 256M
# 2. Ограничьте количество одновременно запускаемых воркеров в pool.d/www.conf:
sudo nano /etc/php/8.2/fpm/pool.d/www.conf
pm.max_children = 50
# 3. Перезапустите службу:
sudo systemctl restart php8.2-fpmШаг 3: Настройка файла подкачки (Swap) как буфера безопасности
# 1. Проверка текущего состояния памяти и Swap:
free -h
# 2. Если Swap отсутствует или мал, создайте Swap-файл на 4 ГБ:
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 3. Добавление в /etc/fstab для автозагрузки:
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstabТиповые ошибки администраторов
- Установка memory_limit = -1 (unlimited): Один неоптимизированный скрипт с утечкой памяти в цикле способен забрать 100% RAM сервера и обрушить СУБД MySQL вместе с веб-сервером.
- Защита процесса php-fpm через oom_score_adj: Если принудительно запретить ядру убивать php-fpm, OOM-Killer убьет демон MySQL (mysqld), что приведет к полному отказу базы данных.
Специалисты ITSTM оптимизируют потребление памяти веб-приложениями, найдут утечки в фоновых воркерах и сбалансируют системные лимиты.
Частые вопросы (FAQ)
Почему OOM-Killer убивает именно PHP-FPM, а не MySQL?
OOM-Killer выбирает жертву с наивысшим баллом oom_score, который зависит от процента занимаемой оперативной памяти и времени жизни процесса. Разросшийся воркер PHP часто становится главной мишенью.
Как найти конкретный PHP-скрипт, который вызвал OOM?
Включите php-fpm slowlog с коротким таймаутом (request_slowlog_timeout = 5s) и сопоставьте время срабатывания OOM в dmesg с записями в slowlog.
Поможет ли увеличение Swap решить проблему навсегда?
Нет. Swap предотвращает аварийный краш ядра, но активная работа со Swap (Thrashing) замедляет сервер в сотни раз. Требуется устранение утечек памяти в коде.
Что такое vm.overcommit_memory в Linux?
Это параметр ядра, управляющий выделением виртуальной памяти. Режим overcommit_memory=2 запрещает выделение памяти сверх физического лимита RAM+Swap, предотвращая внезапные OOM-падения.