Что было. Небольшая машина с 1,5 ГБ памяти и 2 ГБ подкачки, стек Apache + PHP + MySQL. Раз в несколько дней сервер зависал и требовал жёсткой перезагрузки; в журнале ядра OOM-killer. Мониторинг показывал нормальное потребление, а затем резкий скачок.
Что нашли. Настройки Apache по умолчанию (MaxClients 150, десятки запасных потоков) позволяют запустить сотни рабочих процессов; при обходе сайта поисковым роботом одновременных запросов становится много, каждый процесс с PHP занимает десятки мегабайт, память исчерпывается за секунды. Автор снизил лимиты до MaxClients 15 и малых запасных значений; сбои стали реже, но один повторился, и причина осталась смешанной (соседние службы тоже ели память). Отмечено решённым условно.
Как считать лимит для Apache.
- Память одного рабочего процесса:
ps -ylC apache2 --sort:rss | awk '{sum+=$8; n++} END {print sum/n/1024 " MB"}'(для prefork с PHP-модулем типично 30–80 МБ). - Свободная память под Apache: всё минус ОС (~200 МБ), MySQL (его
innodb_buffer_pool_sizeплюс ~100 МБ), прочие службы. MaxRequestWorkers = свободная память / память процесса. На 1,5 ГБ это 8–12, не 150.- В
/etc/apache2/mods-available/mpm_prefork.conf:StartServers 2,MinSpareServers 2,MaxSpareServers 4,MaxRequestWorkers 10,MaxConnectionsPerChild 1000(перезапуск процессов защищает от утечек). Перезапустить Apache.
Что лучше сделать вместо тонкой настройки prefork.
- Перейти на
mpm_event+php-fpm: Apache обслуживает статику и соединения лёгкими потоками, а PHP живёт в отдельном пуле с собственным лимитом (pm.max_children), который считается так же. Это стандарт для современных Ubuntu. - Ограничить MySQL:
innodb_buffer_pool_size256–384 МБ на такой машине,performance_schema = OFF, разумныеmax_connections. - Добавить подкачку 1–2 ГБ (уже была) и
vm.swappiness=10: подкачка не решает, но даёт время OOM-killer’у не срабатывать на коротком пике. - Убрать лишнее: мониторинг с веб-интерфейсом, панели, торрент-клиенты и прочее, что «поставили попробовать», на 1,5 ГБ роскошь.
- Кэш страниц (модуль кэширования или обратный прокси) для анонимных запросов: роботы получают готовый HTML, PHP не запускается.
Как поймать виновника до падения. dmesg -T | grep -A20 -i "out of memory" покажет таблицу процессов на момент OOM: кто съел больше всего, там и настраивать. Мониторинг с интервалом 10 секунд (vmstat 10, free -m в лог) ловит пик, который пятиминутный мониторинг пропускает.
Параметр описан в документации Apache.