Вибір модуля MPM
MPM (Multi-Processing Module) визначає, як Apache обробляє паралельні з'єднання. Від вибору MPM залежить, скільки пам'яті йде на кожен запит і наскільки добре сервер сумісний з PHP-FPM:
| MPM | Застосування | Рекомендація |
|---|---|---|
| Prefork | mod_php (застарілий) | Не рекомендується |
| Worker | Багатопотоковий | Якщо немає mod_php |
| Event | Асинхронний | Рекомендується для PHP-FPM |
# Перемикання на Event MPM
a2dismod mpm_prefork
a2enmod mpm_event
a2enmod proxy_fcgi setenvif
a2enconf php8.2-fpm
systemctl restart apache2
Prefork створює окремий процес на кожне з'єднання і тримає його відкритим до завершення запиту — при mod_php це неминуче, але з PHP-FPM сенсу в цьому більше немає, а пам'ять витрачається багаторазово надлишково.
Реальні помилки і попередження в логах
Найчастіше попередження при нестачі воркерів під навантаженням:
[mpm_event:error] AH00485: scoreboard is full, not at MaxRequestWorkers
[mpm_event:error] server reached MaxRequestWorkers setting, consider
raising the MaxRequestWorkers setting
Воно означає, що всі доступні воркери зайняті обробкою запитів, і нові з'єднання стають у чергу або відхиляються. Причина зазвичай не в самому Apache, а в повільних PHP-скриптах, які тримають воркер довше, ніж потрібно, — спершу варто перевірити slow.log, а вже потім піднімати ліміт. Друга часта помилка виникає при неправильному підключенні PHP-FPM:
[proxy_fcgi:error] AH01079: failed to make connection to backend:
httpd-UDS
Вона означає, що Apache не може достукатися до сокета PHP-FPM — або демон PHP-FPM не запущено, або шлях до сокета в конфігу проксування не збігається з реальним.
Оптимізація KeepAlive
# /etc/apache2/apache2.conf
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5 # Знизити з 15 до 5 секунд
KeepAliveTimeout, виставлений занадто високо, тримає воркер зайнятим в очікуванні наступного запиту від того самого клієнта, навіть якщо клієнт уже закрив вкладку. На сайтах з високою відвідуваністю це швидко з'їдає пул воркерів даремно.
Увімкнення модулів оптимізації
a2enmod expires deflate headers
a2enmod http2 # Підтримка HTTP/2
Логування повільних запитів
# У конфігурації VirtualHost
CustomLog ${APACHE_LOG_DIR}/slow.log combined env=slow
SetEnvIf X-Request-Start t=([0-9]+) slow_start=$1
Як увімкнути mod_status для діагностики
Щоб бачити кількість зайнятих і вільних воркерів у реальному часі, увімкніть модуль і обмежте доступ до сторінки статусу лише з локальної адреси:
a2enmod status
# /etc/apache2/mods-enabled/status.conf
<Location "/server-status">
SetHandler server-status
Require local
</Location>
Директива Require local критична: без неї сторінка статусу, що показує внутрішні URL та IP-адреси клієнтів, стає доступною будь-якому відвідувачу ззовні.
Розрахунок MaxRequestWorkers за пам'яттю
Значення MaxRequestWorkers, виставлене навмання, — часта причина як помилки «scoreboard is full», так і зворотної проблеми, свопу при нестачі пам'яті. Правильний розрахунок відштовхується від обсягу RAM, а не від кількості ядер CPU:
- Визначте середнє споживання пам'яті одним процесом Apache через
ps aux | grep apache2і колонку RSS - Відніміть від загальної RAM сервера пам'ять, зарезервовану під MySQL, PHP-FPM і систему
- Поділіть пам'ять, що залишилася, на середнє споживання одного процесу — це і є безпечна верхня межа MaxRequestWorkers
Коли тюнінг Apache не дасть результату
- Вузьке місце не у вебсервері, а в самих SQL-запитах чи у зовнішньому API — MPM і KeepAlive не пришвидшать те, що й так чекає відповіді бази даних
- PHP-скрипти тримають воркер секундами через синхронні виклики сторонніх сервісів — тут потрібна черга завдань чи кешування відповіді, а не налаштування Apache
- Сервер фізично вичерпав ресурси CPU чи пам'яті — підвищення MaxRequestWorkers на вичерпаному залізі призведе не до зростання продуктивності, а до свопу і повного зависання
- Сайт уже стоїть за Nginx як reverse proxy перед Apache — частину оптимізацій (наприклад, gzip) правильніше налаштовувати на рівні Nginx, а не дублювати в Apache
Перевірка результату
- Перевірте, які модулі реально активні:
apachectl -M | grep mpmмає показати саме event, а не prefork - Прожену навантажувальний тест до і після змін:
ab -n 1000 -c 50 https://yourdomain.com/і порівняйте середній час відповіді - Поспостерігайте за
mod_status(/server-status) кілька хвилин під реальним навантаженням — кількість зайнятих воркерів не повинна впиратися в ліміт постійно
Оптимізацію самого PHP-FPM, включно з розміром пулу і кількістю дочірніх процесів, розбирає стаття PHP-FPM: пули, воркери і оптимізація. Загальні правила .htaccess для прискорення віддачі статики — у статті .htaccess: правила редиректів і оптимізації.