Когда WordPress грузится медленно, проблема почти всегда лежит не в одной точке. Узкое место может быть в PHP (PHP-FPM), в базе (MySQL), в диске, в сети или в очередях (когда запросы ждут свободных рабочих процессов). Профилирование нужно, чтобы перестать гадать и увидеть, где именно растёт время.
Начните с того, что отделите «время до первого ответа» от «время на обработку». В браузере это выглядит как долгий TTFB (time to first byte), а в серверных логах обычно проявляется как долгие запросы к PHP или MySQL. Для практики полезно снять пару трассировок: один раз «в момент проблемы» и один раз «в нормальном режиме».
Быстрое разделение: PHP vs MySQL
Самый удобный способ разделить нагрузку по слоям — смотреть в логах Nginx/Apache, PHP-FPM и MySQL одновременно.
- Nginx часто пишет время выполнения проксирования на upstream (php-fpm). Если время там растёт, значит PHP начинает обрабатывать медленно или все PHP-пулы заняты.
- PHP-FPM может показать, какой запрос выполнялся долго (slowlog) и сколько было занято воркеров.
- MySQL slow query log даст список запросов, которые превышают порог, и тогда станет понятно, какие именно SQL тормозят страницу.
Если у вас есть только один источник (например, только логи веб-сервера), вы будете упираться в симптомы, а не в причину. Для медленной загрузки WordPress на VPS обычно требуется минимум двух источников: PHP-FPM и MySQL.
Минимальный набор метрик перед вмешательствами
Перед тем как менять конфиги, полезно зафиксировать «базовую картину». Это ускоряет расследование и помогает не сделать хуже.
- загрузка CPU и iowait (диск может быть реальной причиной)
- активные соединения MySQL и число запросов в минуту
- состояние очередей PHP-FPM: занятые и доступные воркеры
- наличие ошибок в логах: timeouts, max_children reached, connection refused, lock wait timeout
Отдельно проверьте, нет ли у сервера признаков «ресурсного голода»: если VPS маленький по CPU или медленный по диску, даже хорошая настройка PHP-FPM и MySQL не спасёт без кэша.
Профилирование PHP-FPM на VPS: slowlog, очереди и реальные причины задержек
Профилирование PHP-FPM отличается от «просмотра кода». Вам нужно получить измеримые признаки: какие запросы к PHP занимают много времени, в каком месте PHP-FPM простаивает, и почему пул не успевает обслуживать входящий трафик.
Самый частый сценарий медленной загрузки WordPress: PHP-FPM упирается в лимит воркеров (max_children), а каждый воркер ждёт MySQL, либо MySQL не отвечает быстро из-за долгих запросов и блокировок. Тогда всё выглядит как «PHP медленный», хотя первопричина в БД.
Включите slowlog PHP-FPM и посмотрите хвосты по времени
Slowlog фиксирует PHP-обработку, которая превышает заданный порог. Это не полноценный профилировщик, но он даёт точные строки: какой запрос PHP выполнялся долго.
Обычно нужные параметры задаются в конфиге пула, например в файле вида php-fpm.d/www.conf. Ищите блоки вроде slowlog и requestslowlogtimeout.
Пример логики настройки (значения подбираются под нагрузку и допустимый объём логов, а не «по умолчанию навсегда»):
«`ini ; Внутри секции pool requestslowlogtimeout = 2s slowlog = /var/log/php-fpm/www-slow.log «`
После изменения перезапустите PHP-FPM и дождитесь нескольких медленных запросов.
Дальше смотрите:
«`bash sudo tail -n 200 /var/log/php-fpm/www-slow.log «`
Важный момент: slowlog покажет стек выполнения и поможет понять, где именно зависает WordPress (например, в загрузке плагинов, в обращениях к базе, в каких-то внутренних хуках). Если в стеке видно ожидание БД, переходите к профилированию MySQL.
Проверьте параметры пула: pm, max_children и Saturation
PHP-FPM работает пулами. Когда пул «насыщен», новые запросы ждут свободного воркера, и это сразу увеличивает время ответа для пользователя.
Посмотрите текущую конфигурацию пула:
- pm: mode управления воркерами (static/dynamic/ondemand)
- pm.max_children: максимальное число одновременных PHP-запросов
- pm.startservers / pm.minspareservers / pm.maxspare_servers: как пул масштабирует количество воркеров
- requestterminatetimeout: ограничение по времени выполнения
- slowlog: как уже говорили
Если max_children слишком мал, вы получите очереди и рост TTFB. Если слишком велик, вы рискуете перегрузить CPU или упереться в память, а тогда система начнёт «душиться» свопом или планировщиком.
Типичный симптом в логах PHP-FPM: сообщения о достижении лимитов, а в веб-логах — рост числа долгих запросов. Идея профилирования тут простая: узнать, когда пул насыщается и насколько долго он не может догнать входящий поток.
Включите страницу статуса PHP-FPM (если безопасно)
У PHP-FPM есть статусная страница, которую можно включить для оценки состояния пула: занятые воркеры, активные запросы, очередь. Это не всегда удобно в проде, но как инструмент расследования часто помогает.
Если у вас Nginx, конфигурация обычно выглядит как отдельный location с ограничениями по IP и авторизацией. Смысл не в конкретных директивах, а в том, чтобы открыть статус только для себя и временно.
Смотрите на состояние в момент, когда страница грузится медленно. Если заняты почти все воркеры, а новых ждать дольше секунды, значит проблема может быть не в одном запросе, а в общей пропускной способности.
Наблюдение на уровне метрик: php-fpm_exporter и Grafana
Если у вас уже есть Prometheus/Grafana, имеет смысл подключить экспортёр для PHP-FPM. Он отдаёт метрики: количество активных запросов, время выполнения, состояние воркеров. Тогда корреляция между «плохим периодом» и «что происходило внутри пула» станет очевидной.
При расследовании медленной загрузки WordPress на VPS полезно смотреть связку в одном окне графиков:
- active processes PHP-FPM растут
- одновременно растёт число slow requests (или slowlog становится «молчаливее»/«шумнее»)
- параллельно в MySQL увеличиваются long-running queries или time spent in lock
Профилирование MySQL: slow query log, EXPLAIN и блокировки
MySQL в связке с WordPress редко «просто медленный». Обычно есть конкретные запросы или паттерны нагрузки: плохо индексированные выборки, тяжёлые джойны, долгие транзакции, блокировки на InnoDB или переполненная очередь на диск.
Задача профилирования MySQL — собрать точные SQL, которые дают вклад в медленную загрузку. Без этого любые настройки буферов превращаются в шаманство.
Включите slow query log и соберите «лидеров» по времени
Включите slow query log и настройте порог так, чтобы ловить реально проблемные запросы. Слишком низкий порог даст огромные логи, слишком высокий может пропустить основную проблему.
Идея в следующем:
- сначала поймать набор запросов, которые происходят часто и занимают много времени
- потом углубиться в каждый тип запроса: план выполнения, индексы, фильтры, количество строк
Дальше анализ выполняйте так:
- отсортируйте записи по времени выполнения и количеству повторов
- для топовых запросов прогоните EXPLAIN (или EXPLAIN ANALYZE, если доступно в вашей версии)
- проверьте, есть ли подходящие индексы и как меняются планы
Пример базовой проверки плана:
«`sql EXPLAIN SELECT … «`
Если план показывает, что MySQL сканирует много строк (например, type=ALL или большие estimations), это почти всегда индексация. Если план меняется странно из-за статистики — поможет анализ таблиц и корректировка индексов.
Проверьте блокировки и long-running queries
Даже хорошо индексированный запрос может тормозить, если он ждёт блокировку. WordPress использует транзакции в админских действиях, при обновлениях кэша, при массовых операциях и иногда при фоновых задачах.
На практике смотрите:
- есть ли длительные запросы, которые продолжают выполняться без завершения
- есть ли ошибки типа Lock wait timeout exceeded
- растёт ли число lock waits в InnoDB
Если видно, что большинство «медленных» записей в slow query log связаны с одинаковой таблицей и длительными ожиданиями, первым шагом будет понять источник блокировки: кто держит транзакцию и почему.
Индексы для WordPress: проверка узких мест на уровне схемы
WordPress типично нагружает несколько таблиц: wpposts, wppostmeta, wpoptions, wpcomments. Но тормозит не сама таблица, а конкретные запросы к ней.
Проверьте частые запросы из slow log:
- выборки по metakey/metavalue в wp_postmeta
- выборки по комбинациям полей в wpposts (posttype, post_status, date)
- обращения к wp_options, особенно если включены автозагружаемые опции
Если в запросе фильтруется по полю, а индекс отсутствует или индекс «не тот», MySQL будет читать много строк. Индекс решает проблему радикально, но требует аккуратности: добавление индекса ускоряет чтение и замедляет записи. Для WordPress это обычно приемлемо, если индексы адресуют именно горячие запросы.
InnoDB настройки: когда буферы действительно помогают
Размер buffer pool и поведение InnoDB влияют на повторное чтение страниц с диска. Но менять их стоит только после того, как вы понимаете, что именно стоит за задержками.
Обычно логика такая:
- если много «read from disk» и медленная работа с таблицами, увеличением buffer pool вы снижаете стоимость чтения
- если запросы тормозят из-за блокировок, настройки буферов не помогут
- если тормозит запись из-за fsync на диске, проблема может быть в хранилище, а не в MySQL
Профилирование MySQL в связке с системными метриками: если iowait высокий, MySQL может казаться виноватым, хотя виноват диск. Поэтому смотрите на уровне VPS: какая нагрузка на диск, нет ли очередей, не падают ли дисковые IOPS.
Как связать профилирование PHP-FPM и MySQL: поиск первопричины
Иногда slowlog PHP-FPM показывает долгие запросы, но не говорит, почему они такие. Инструмент профилирования становится ценным, когда вы можете связать события по времени: PHP ждал не просто «долго», а конкретно потому, что MySQL выполнял определённые запросы, удерживал блокировки или не успевал обслуживать соединения.
Корреляция: совпадают ли пики PHP и пики MySQL
Сделайте простую проверку по времени:
- найдите период, когда пользователи жалуются
- посмотрите в slow query log MySQL, какие запросы выполнялись дольше всего в этот же промежуток
- в slowlog PHP-FPM посмотрите, в какие секунды были долгие PHP запросы
Если совпадение плотное, это сильный аргумент, что узкое место в БД или в сетевом канале до БД. Если же MySQL в этот период относительно ровный, а PHP-FPM «тянет», возможно причина в PHP-слое: тяжелые циклы, неоптимальные плагины, отсутствие кэша, DNS, блокировки в приложении.
Очереди и насыщение: почему max_children влияет на MySQL
Когда PHP-FPM раздувает параллелизм (или просто не успевает), он открывает больше одновременных запросов к MySQL. Даже небольшой запрос может стать проблемой, если он выполняется сотни раз одновременно и конкурирует за ресурсы.
В результате вы видите классическую картину:
- PHP-FPM упирается в очередь воркеров
- количество активных соединений к MySQL растёт
- MySQL начинает дольше отвечать на все запросы
- в slow query log появляется всё больше записей
Это не означает, что нужно «уменьшить PHP», чтобы всё прошло. Нужно поймать баланс:
- сколько PHP-запросов в секунду реально нужно
- сколько запросов MySQL выдерживает без деградации
- какие конкретно SQL тормозят и должны быть ускорены индексами/кэшем
Конкуренция соединений: limits и пуллинг
WordPress обычно создаёт короткоживущие запросы к MySQL. Но число параллельных PHP воркеров влияет на число одновременных соединений/запросов.
Проверьте, нет ли признаков:
- слишком много активных соединений
- частые реконнекты
- ошибки на уровне connection limit (если настроены лимиты)
Если вы используете ProxySQL или кеширующий слой — добавьте его в картину. Если нет, то базовое правило такое: сначала устраняйте причины долгих запросов, а затем подстраивайте concurrency.
Кэш как связующий слой: когда нужно не «донастраивать», а «разгрузить»
Даже идеально настроенный PHP-FPM не заменит кэширование, если WordPress каждый раз заново генерирует тяжёлые запросы. Поэтому в расследование медленной загрузки WordPress почти всегда нужно включать кэш:
- page cache (для страниц)
- object cache (для повторно используемых данных и результатов запросов)
- opcode cache (для ускорения выполнения PHP-кода)
Если объектный кэш отключен, WordPress будет чаще обращаться к MySQL. В итоге любое «едва заметное» замедление БД становится заметным на фронте.
На практике это похоже на магазин с очередью: если каждый посетитель заново рассчитывает цену, касса всегда будет перегружена. Кэш — это как подготовленный прайс-лист, который сокращает количество вычислений.
Практический план: что делать, чтобы найти причину за 1–2 часа
Ниже план в стиле «минимум действий, максимум информации». Он подходит для VPS с WordPress, где нужно разобраться, почему загрузка страницы стала медленной.
Шаг 1. Зафиксируйте момент и воспроизведите проблему
Выберите URL, который грузится медленно: главная, карточка товара/поста, страница категорий. Воспроизведите 3–5 раз подряд и одновременно снимите базовые метрики:
- CPU и iowait
- состояние диска (если мониторите)
- активность MySQL (активные запросы)
- состояние PHP-FPM (если есть status)
Ключевой момент: смотрите именно в тот момент, когда «всё плохо». Если вы проверите через час, когда нагрузка ушла, доказательств не останется.
Шаг 2. Включите или временно усилите slowlog в PHP-FPM
Добавьте requestslowlogtimeout и включите slowlog (или временно снизьте порог, если slowlog сейчас не показывает ничего).
Параллельно убедитесь, что логи доступны и ротация не убьёт данные за ночь. Затем перезапустите PHP-FPM и повторите запрос к проблемной странице.
Если в slowlog появляются стеки, где часто встречается работа с базой (например, запросы к wpdb), это ваш мост к MySQL.
Шаг 3. Включите slow query log в MySQL и поймайте топ запросы
Включите slow query log с адекватным порогом. Перейдите по проблемному URL и дождитесь появления записей.
Дальше выпишите:
- 5–10 запросов с максимальным временем
- 5–10 запросов с наибольшей частотой
Если среди топов есть запросы к wpoptions, wppostmeta или тяжёлые выборки по wp_posts с фильтрами, это почти гарантированная точка для ускорения индексами или кэшем.
Шаг 4. Для топ запросов прогоните EXPLAIN и проверьте индексы
Для каждого топ запроса:
- выполните EXPLAIN
- посмотрите, как MySQL строит план: использует ли индексы, какой тип сканирования
- сравните условия WHERE и индексы (если индексов нет — запрос обречён сканировать много строк)
Не пытайтесь чинить всё сразу. Обычно один-два запроса делают львиную долю боли.
Шаг 5. Проверьте насыщение PHP-FPM: сколько воркеров занято
Пока вы повторяете запрос к странице, откройте статус PHP-FPM или смотрите метрики. Если активных воркеров почти максимум, значит PHP-FPM перестаёт успевать, и даже ускорение одного SQL не всегда даст мгновенный эффект.
Тогда вам нужен либо временный буфер (немного увеличить пропускную способность пула), либо стабильное кэширование, либо ускорение горячих SQL так, чтобы запросы в среднем стали короче.
Шаг 6. После фикса проверьте не только скорость, но и стабильность
Поставьте цель: не только ускорить один URL, но и снизить хвосты по времени. Сравните:
- количество записей slowlog PHP-FPM
- количество записей slow query log
- среднее и хвостовое время TTFB (если измеряете)
Если хвосты исчезли, нагрузка стала предсказуемой — это главный показатель, что вы нашли первопричину.
Типичные ошибки при профилировании: почему «меняли всё» и стало только хуже
Ошибки обычно возникают, когда меняют настройки без измерений или когда подменяют причину симптомом.
Ошибка 1. Лечить PHP-FPM, не видя MySQL
Например, увеличили max_children, и нагрузка вроде выросла, но MySQL начал отвечать медленнее. Итог: пользователи снова видят задержки, а сервер в целом деградирует.
Правильный подход: сначала поймать топ SQL в MySQL, потом уже аккуратно регулировать PHP-FPM concurrency.
Ошибка 2. Слишком долгий slow query log период или неправильный порог
Если порог слишком высокий, вы поймаете редкие хвосты и решите проблему не там. Если порог слишком низкий — логи станут шумом, и станет тяжело выделить реальные причины.
Правильнее: подобрать порог так, чтобы в расследовании было ограниченное число записей и они соответствовали наблюдаемым задержкам.
Ошибка 3. Изменения без корреляции во времени
Если вы включили slowlog и тут же меняли конфиги, вы не сможете понять, что именно повлияло. Сначала соберите данные, потом меняйте.
Ошибка 4. Игнор диска и iowait
MySQL часто считает дисковое чтение «внутренней задержкой», но первопричина может быть в VPS-хранилище. Если iowait высокий, ускорять индексы и увеличивать буферы может быть недостаточно: система всё равно ждёт диск.
Ошибка 5. Проблемы из-за DNS и сети
Если WordPress или плагины делают DNS-запросы во время генерации страницы, это может приводить к странным задержкам в PHP, и вы будете искать причину в MySQL. Смотрите на трассы медленных операций: иногда причина вообще не в запросах к БД.
Оптимизации после профилирования: что менять в PHP-FPM и MySQL
Когда вы уже видите топ причин, можно переходить к изменениям. Главное правило: менять точечно и проверять эффект на тех же URL.
PHP-FPM: настройка пула под реальную нагрузку
Базовые рычаги:
- привести pm в режим, который соответствует характеру нагрузки (обычно dynamic/ondemand дают гибкость, но выбор зависит от профиля запросов)
- подобрать max_children так, чтобы не упираться в очередь слишком часто
- установить requestterminatetimeout и корректные timeouts, чтобы подвисшие запросы не забивали пул
- оставить slowlog включённым на время проверки и отключить после, чтобы не генерировать лишний объём логов
Если slowlog показывает, что большинство запросов ждёт MySQL, то увеличение max_children может ухудшить ситуацию. В таком случае лучше вначале ускорить запросы в MySQL или разгрузить их кэшем.
MySQL: ускорение топ-запросов и снижение блокировок
На уровне MySQL почти всегда выигрывают следующие направления:
- добавить или поправить индексы под условия WHERE
- устранить N+1 запросы со стороны WordPress/плагинов (это уже ближе к приложению, но проявляется в SQL)
- сократить время транзакций, чтобы уменьшить блокировки
- проверить статистику и актуальность схемы после изменений
Если блокировки доминируют, настройка буферов не будет тем рычагом, который решает задачу. Там нужен разбор транзакционных конфликтов: какие операции запускаются одновременно и почему они держат блокировку дольше, чем должны.
Кэш WordPress: разгрузить связку PHP-FPM и MySQL
Самый частый итог профилирования: вы находите «медленные запросы», но их повторяемость слишком высока, и даже небольшие задержки повторяются многократно.
Тогда кэширование даёт устойчивый эффект:
- объектный кэш снижает количество обращений к MySQL
- page cache уменьшает число генераций страниц
- opcode cache снижает накладные расходы на PHP-код
Для расследования это важная проверка: включите кэш временно в тестовом режиме (или на короткий период), и если TTFB резко сокращается, значит основная стоимость действительно в вычислении и обращениях к БД, а не в сети или диске.
Системный уровень: диск, CPU, лимиты
Иногда профилирование PHP-FPM и MySQL приводит к простому выводу: VPS физически не тянет нагрузку. Тогда вы увидите признаки:
- iowait растёт вместе с задержками
- в MySQL медленные операции связаны с чтением
- CPU в основном занят не приложением, а ожиданием или контекстными переключениями
Тогда вместо долгих правок конфигов рациональнее:
- улучшить тип хранения (SSD/NVMe, нормальные IOPS)
- пересмотреть размер VPS
- ограничить параллелизм и включить кэш, чтобы снизить нагрузку
Чеклист: что собрать перед тем, как принять решение по изменениям
Чтобы изменения были осмысленными, соберите данные в одном месте. Этот чеклист помогает не потеряться и не повторять действия.
- Запрос/URL, который тормозит, и время, когда он тормозит
- Значения из логов PHP-FPM slowlog: какие стеки и какие операции повторяются
- Топ запросов из MySQL slow query log: по времени и по частоте
- EXPLAIN для топ запросов и список индексов, которые используются/не используются
- Метрики состояния PHP-FPM в момент проблемы: занятые воркеры и очереди
- Признаки блокировок в MySQL (long-running/lock waits)
- Метрики VPS: CPU, iowait, активность диска
- Информация о включённом кэше в WordPress (page/object/opcode) и о том, что менялось перед ухудшением
Итог: как сделать профилирование PHP-FPM и MySQL рабочим инструментом, а не «игрой в догадки»
Профилирование PHP-FPM и MySQL на VPS для разборa медленной загрузки WordPress работает, когда вы идёте по цепочке: сначала фиксируете хвосты по времени, затем находите конкретные места внутри PHP и внутри базы, и только после этого меняете настройки.
Если в slowlog PHP-FPM видно, что запросы ждут MySQL, усиливайте профилирование MySQL и ускоряйте топовые SQL через индексы и снижение блокировок. Если же MySQL не показывает проблемных запросов, возвращайтесь к PHP-слою: смотрите поведение пулов, очереди, работу плагинов и наличие кэша.
Сделайте минимальный цикл «данные → гипотеза → проверка на тех же URL». Тогда вы не будете настраивать VPS вслепую, а получите измеримый результат: уменьшатся slow requests, станет меньше дорогих SQL и снизится TTFB для пользователей.
