Виртуальная машина на 2 ГБ без подкачки с Apache, PHP и MySQL регулярно ловит OOM-killer: подкачка, лимиты воркеров и лишние службы

Что было. Учебный проект на арендованной виртуальной машине: один vCPU, 2 ГБ памяти, подкачка не настроена. Debian 11, Apache с PHP-модулем, MySQL, плюс оставшиеся от курса мониторинг и визуализация метрик. Периодически OOM-killer убивает процессы; в top процессы веб-сервера и MySQL занимают около 80 % памяти.

Что советовали участники.

  1. Подкачка. Её отсутствие превращает любой пик в убийство процесса; 1–2 ГБ файла подкачки дают буфер (об этом отдельный разбор).
  2. Ограничить Apache. MaxConnectionsPerChild 1000 (перезапуск процессов против утечек) и посчитанные лимиты MaxRequestWorkers/ServerLimit в mpm_prefork.conf под реальную память процесса.
  3. Остановить лишнее. Стек мониторинга и панели визуализации на 2 ГБ рядом с базой это половина памяти на инструменты. systemctl disable --now для того, что не нужно проекту.
  4. Смотреть правильно. htop по памяти, dstat во времени, journalctl -k | grep -i oom для точной картины; и не убивать процессы Apache вручную, они тут же пересоздаются, вместо этого systemctl restart apache2 или a2dissite.
  5. Добавить памяти, если после всего этого нагрузка не помещается: 2 ГБ для LAMP с MySQL это нижняя граница.

Наш расчёт для такой машины.

Компонент Разумный лимит
ОС и службы ~250 МБ
MySQL (innodb_buffer_pool_size) 256–384 МБ, performance_schema = OFF
Apache prefork с PHP 8–10 процессов × ~50 МБ = ~500 МБ
Запас под пики и кэш файлов остальное
При таких лимитах машина держит небольшой сайт стабильно; при большем трафике нужен mpm_event + PHP-FPM и кэш страниц, а не рост MaxRequestWorkers.

Как убедиться, что подкачка не стала костылём. vmstat 5: столбцы si/so должны быть нулями почти всегда; постоянный обмен означает, что рабочая нагрузка не помещается, и лечится это памятью или сокращением нагрузки, а не размером файла подкачки.

Что делать в момент инцидента. dmesg -T | grep -B3 -A25 'Out of memory' покажет, кто вызвал и кого убили; часто это не веб-сервер, а фоновый процесс мониторинга или задача резервного копирования, запущенная в час пик. Перенести тяжёлое на ночь и защитить базу OOMScoreAdjust=-500 в её юните.

Модуль prefork описан в документации Apache.