Когда 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 и настройте порог так, чтобы ловить реально проблемные запросы. Слишком низкий порог даст огромные логи, слишком высокий может пропустить основную проблему.

Идея в следующем:

  • сначала поймать набор запросов, которые происходят часто и занимают много времени
  • потом углубиться в каждый тип запроса: план выполнения, индексы, фильтры, количество строк

Дальше анализ выполняйте так:

  1. отсортируйте записи по времени выполнения и количеству повторов
  2. для топовых запросов прогоните EXPLAIN (или EXPLAIN ANALYZE, если доступно в вашей версии)
  3. проверьте, есть ли подходящие индексы и как меняются планы

Пример базовой проверки плана:

«`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 для пользователей.

От mpns_by