nginx и PHP-FPM - разделение статики, пулы, разбор медленных ответов
Разбираемся, как связка веб-сервера и PHP обслуживает сайт, и находим, где именно теряется время ответа посетителю.
Решение
Смотрим, кто что обслуживает:
# статика уходит с диска мимо PHP, динамика - в сокет процессов PHPgrep -rn 'location ~\|fastcgi_pass\|proxy_pass' /etc/nginx/bx/conf/*.conf | headss -x | grep php-fpm | head -3 # сокеты пулов PHPВеб-сервер отдаёт картинки, стили и скрипты сам, без участия PHP. Всё остальное он передаёт процессам PHP через сокет, и время ответа складывается из ожидания свободного процесса и работы самого кода.
Смотрим настройки пула сайта:
# у каждого сайта пула свой файл: пределы задаются на сайт, а не на серверgrep -E 'pm|max_children|max_requests|listen' /etc/php-fpm.d/bx0.conf# число процессов подбирают под объём памяти, а не по совету из интернетаЧисло процессов определяет, сколько запросов сайт обслуживает одновременно. Слишком маленькое значение выстраивает очередь при первом же наплыве посетителей, слишком большое съедает всю память и приводит к тому же результату другим путём.
Разбираем медленные ответы:
# журнал медленных запросов: показывает, в какой функции застрял процессgrep -n 'slowlog\|request_slowlog_timeout' /etc/php-fpm.d/bx0.conftail -40 /var/log/php-fpm/bx0-slow.log 2>/dev/nullЖурнал медленных запросов называет конкретное место в коде, а не просто время. Это отличает «сайт медленный» от «медленный один запрос к внешнему сервису внутри одного компонента».
Проверяем, где именно теряется время:
# время ответа веб-сервера и время работы PHP пишутся отдельноtail -20 /var/log/nginx/access.log | awk '{print $NF, $7}' | tail -10# большая разница между ними - очередь к процессам PHP, а не медленный код# число процессов в пуле считают от памяти узла, а не от числа посетителейРазделение времени на ожидание и выполнение сразу отсекает половину гипотез о причинах. Долгое ожидание лечится числом процессов и кэшированием, а долгое выполнение - уже правкой самого кода страницы.
Кэширование меняет картину нагрузки сильнее любых настроек самого пула. Композитный режим и кэш компонентов убирают из-под PHP основную долю запросов, и связке остаётся отдавать готовые файлы. Настраивать число процессов имеет смысл уже после того, как кэш включён и работает, иначе подбор идёт под нагрузку, которой быть не должно.
Связка с Apache нужна далеко не каждому проекту. Она даёт поддержку файлов с локальными правилами доступа, которые часто приносят с общего хостинга, но стоит заметной памяти на каждый процесс. Проект, не зависящий от таких файлов, работает быстрее без неё.
Свои директивы веб-сервера кладут только в отдельные подключаемые файлы. Правки в сгенерированных конфигах живут до первого изменения настроек через меню окружения, и это регулярно принимают за самопроизвольный откат настроек.
Типичные проблемы
Сайт отвечает медленно при небольшой нагрузке.
Процессов в пуле мало, и запросы выстраиваются в очередь. Время ожидания при этом заметно больше времени работы самого кода.
Память кончается при всплеске посещаемости.
Процессов в пуле слишком много для объёма памяти сервера. Каждый процесс держит свою копию PHP и потребляет память независимо от соседей.
Правки конфигурации пропали.
Правки делались в сгенерированных файлах конфигурации. Окружение переписывает их при каждом изменении настроек через своё меню.
Статика отдаётся через PHP.
Правило обработки статических файлов не сработало, и запрос ушёл в PHP. Это хорошо видно по журналу процессов, где вместо страниц появляются картинки.
Ошибки Apache видны посетителям.
Веб-сервер передаёт страницы ошибок второго сервера посетителю как есть. Их перехватывают отдельной настройкой обработки ошибок.
Частые вопросы
Сколько процессов PHP держать?
Столько, сколько помещается в память с запасом: объём памяти делят на реальное потребление одного процесса. Значение подбирают под сайт, готового числа нет.
Нужен ли Apache рядом с nginx?
Только если проект опирается на файлы с локальными правилами доступа. Без них связка из одного веб-сервера проще и экономнее по памяти.
Почему после переезда сайт стал медленнее?
Чаще всего пул настроен по умолчанию, а не под новый сервер. Число процессов и пределы памяти переносят и пересчитывают отдельно.
Где смотреть, что именно тормозит?
В журнале медленных запросов PHP: он показывает место в коде. Журнал веб-сервера отвечает на другой вопрос - сколько времени заняло ожидание.
Смежное
- Журналы сервера: где лежат, что смотреть, ротация - журналы пулов и медленных запросов
- nginx и PHP-FPM - оглавление подтемы
- Переадресация на другой домен - правила на уровне веб-сервера
- Обновление окружения и смена версии PHP - откуда берутся пулы
- Быстрые картинки на витрине: размеры, ленивая загрузка, WebP - что именно отдаёт веб-сервер посетителю
- Сервер и поиск - устройство сервера целиком
- Долгий обмен и обрывы: шаг, память, время выполнения - кто ещё занимает процессы PHP
- Ошибки 500 и 502: где искать причину - что видно снаружи при нехватке процессов
- Сайт тормозит: разбор причин - разбор со стороны приложения
- Редиректы внутри сайта: 301 на раздел, https и старые адреса - правила переходов на том же уровне
- Окружение за прокси и в облаке: адреса, протокол, доступ наружу - когда перед сайтом стоит посредник
- Файл .htaccess на платформе: что работает, что ломает - что из файла работает при этой связке
- Кэш браузера и сжатие статики: заголовки, gzip, обновление - заголовки и сжатие для той же статики
- Веб-сервер вручную: фронтенд, бэкенд, конфигурация - как этот контур собирают без окружения