REST-эндпоинт WordPress под нагрузкой: что ломается первым
Свой REST-эндпоинт может отвечать быстро на тестовых данных и тормозить в проде: сначала из-за дорогого запроса, затем из-за промаха кеша или проверки прав на каждый объект. Разбираем порядок отказов и что измерять.

Первым обычно падает не PHP
В WordPress 6.x собственный REST-эндпоинт чаще упирается не в сам факт обработки HTTP-запроса, а в работу вокруг него: SQL-запрос собирает слишком много строк, проверка прав повторяется для каждого объекта, а кеш не попадает в ключ из-за параметров или пользователя. На тестовой базе всё выглядит нормально. Под нагрузкой каждый промах превращается в новую работу для PHP и базы данных.
Разбирать нужно не одну функцию, а цепочку: маршрутизация, авторизация, выборка данных, формирование ответа и кеширование. Точного универсального порога, после которого endpoint сломается, нет: результат зависит от схемы данных, сервера, плагинов и профиля трафика. Поэтому ниже — порядок проверки и признаки, по которым видно, где именно заканчивается запас.
Путь запроса и первые точки отказа
WordPress регистрирует REST-маршруты на событии rest_api_init. Для своего маршрута нужно определить обработчик и permission_callback. В запросе к эндпоинту сервер сначала проверяет доступ, затем вызывает обработчик. Если права проверяются через дополнительные запросы к базе или внешнюю службу, их цена оплачивается при каждом обращении — в том числе при промахе кеша.
Дальше обработчик получает параметры, читает данные и собирает REST-ответ. Здесь часто появляется дорогой запрос: фильтрация по метаполям, сортировка по вычисляемому значению, широкая выборка с последующей фильтрацией в PHP. Затем ответ сериализуется. Если он большой, растут время обработки, объём памяти и размер передачи по сети.
Кеш не делает дорогой endpoint дешёвым сам по себе. Он лишь позволяет повторно использовать результат, если запросы действительно совпадают и результат безопасно отдавать следующему пользователю.
Под cache stampede понимают ситуацию, когда запись в кеше истекает, и множество одновременных запросов одновременно начинают пересчитывать один и тот же результат. Вместо одного обращения к базе вы получаете целую волну одинаковой работы.
Что ломается первым
1. Запрос к данным
Если endpoint каждый раз выполняет широкий запрос, нагрузка на базу растёт пропорционально числу промахов кеша. Для WordPress особенно внимательно проверяйте фильтры и сортировку по метаполям: структура postmeta не превращает произвольный набор условий в дешёвую выборку. Время запроса может резко измениться, когда объём таблицы вырастет или планировщик выберет другой план.
Проверьте, что выборка ограничена пагинацией, а параметры запроса имеют разумные границы. Не загружайте тысячи записей ради того, чтобы потом оставить двадцать в PHP. Измеряйте SQL-запросы на данных, близких к боевому объёму, и смотрите план выполнения средствами вашей базы. Конкретная команда зависит от используемой СУБД и версии.
2. Проверка прав
Проверка доступа должна быть дешёвой и соответствовать смыслу данных. Если ответ зависит от пользователя, нельзя кешировать общий результат и отдавать его всем, кто пришёл с тем же URL. Особенно опасны ответы с персональными данными, статусом заказа или содержимым, доступным только владельцу.
Не переносите проверку прав целиком в обработчик после чтения данных, если это позволяет сначала выполнить дорогой запрос. Но и не кешируйте результат проверки как глобальный без учёта пользователя, роли и условий доступа. Ошибка здесь может стать утечкой данных, а не просто медленным ответом.
3. Кеш, который почти не попадает
Ключ кеша должен учитывать всё, что меняет ответ: фильтры, сортировку, страницу, язык, а при персонализированной выдаче — и контекст пользователя. Если ключ строится только по пути маршрута, разные запросы могут получить один ответ. Если в ключ включить случайные или нестабильные параметры, кеш будет постоянно промахиваться.
Отдельно решите, где хранится кеш. Транзиенты WordPress могут опираться на базу данных, если сайт не подключил постоянный object cache. Поэтому наличие транзиента ещё не означает, что чтение и запись происходят в Redis или Memcached. Общий кеш на reverse proxy или CDN — другой слой: он может не кешировать запросы с авторизационными заголовками или cookies, а правила зависят от конфигурации инфраструктуры.
4. Одновременное истечение записей
Если популярный ключ истекает в момент всплеска, несколько PHP-процессов могут одновременно начать пересчёт. Наблюдаемый симптом — резкий рост одинаковых SQL-запросов и времени ответа около момента истечения кеша. Проверьте, можно ли сгладить обновление: например, обновлять данные заранее или использовать механизм блокировки пересчёта. Конкретный способ зависит от object cache и архитектуры приложения.
5. Размер ответа и PHP-процессы
Даже быстрый SQL-запрос не спасает, если endpoint возвращает крупный массив, который нужно преобразовать, сериализовать и отправить. Длинная обработка занимает PHP worker; при исчерпании свободных workers новые запросы ждут, а прокси перед приложением может вернуть 502 или 504. Эти статусы сами по себе не доказывают, что проблема в WordPress: смотрите логи PHP-FPM, веб-сервера и базы на одной временной шкале.
Сравните слои кеширования
| Слой | Что ускоряет | Главный риск |
|---|---|---|
| Кеш результата в приложении | Повторное получение данных и сборку ответа | Неполный ключ, неверная инвалидация, stampede |
| Постоянный object cache | Доступ к часто используемым объектам между запросами | Настройка и поведение зависят от плагина и инфраструктуры |
| HTTP-кеш перед WordPress | Повторную отдачу готового HTTP-ответа | Персональные ответы или авторизованные запросы могут попасть не тому клиенту либо обходить кеш |
Это не три взаимозаменяемых решения. HTTP-кеш особенно полезен для публичного ответа, который можно безопасно повторно отдавать разным посетителям. Кеш в приложении подходит, когда нужно контролировать состав ключа и обновление результата. Object cache помогает не выполнять повторную работу с объектами, но не отменяет необходимость проверить SQL и логику доступа.
Как измерять, а не гадать
Сравнивайте одинаковые запросы на одинаковых данных: отдельно холодный кеш, прогретый кеш и момент истечения записи. Для каждого сценария фиксируйте параллельность, параметры запроса, объём ответа и версию WordPress. Прогоняйте не только популярный URL, но и варианты фильтров, страниц и пользователей, которые обходят кеш.
- Измерьте задержку ответа на стороне клиента и время обработки на сервере; смотрите не только среднее, но и высокие перцентили.
- Сопоставьте медленные ответы с длительностью SQL-запросов, количеством запросов и ожиданием свободного PHP worker.
- Проверьте долю попаданий в каждый слой кеша и отдельно посчитайте запросы, которые намеренно обходят его.
- Запишите размер ответа и расход памяти на обработке. Маленький ответ в тесте не гарантирует такой же профиль в проде.
- Повторите тест после обновления WordPress, плагина кеширования или схемы данных: сравнивайте одинаковые условия, а не цифры из разных окружений.
Не делайте вывод по одному успешному прогону. Нагрузка может проявиться только при одновременном истечении кеша, редком фильтре или прогреве после деплоя. Полезно отдельно проверить поведение, когда кеш недоступен: endpoint должен либо корректно выполнить запрос, либо контролируемо отказать, а не породить лавину повторов.
Границы решения
Кеш не исправит запрос, который плохо масштабируется с ростом таблицы. Он также не решит проблему, если каждый пользователь получает уникальный ответ, а инфраструктура не умеет безопасно кешировать его отдельно. В таком случае важнее уменьшить объём выборки, разделить публичные и персональные данные или пересмотреть способ построения ответа.
Инвалидация кеша — отдельная задача: здесь речь только о том, как нагрузка проявляется при чтении и промахах. У публичного ответа допустимое время устаревания может отличаться от требований к данным личного кабинета. Если актуальность критична, определите её явно, а не выбирайте срок кеширования по удобству.
Что делать дальше
Начните с одного реального маршрута и соберите профиль запроса: кто его вызывает, какие параметры меняют результат, где выполняется проверка прав и какие SQL-запросы идут при промахе. Затем нагрузочно проверьте холодный кеш и одновременное истечение записи. Только после этого выбирайте слой кеширования и правила ключа.
Для WordPress 6.x сверяйте регистрацию маршрута и обработку ответа с документацией соответствующей версии; плагины кеширования и серверная конфигурация могут менять поведение HTTP-кеша. После внедрения следите в проде за перцентилями задержки, ошибками 5xx, временем SQL и долей попаданий в кеш. Именно эта связка покажет, что сломалось первым.
Проверка грамотности: Орфография, пунктуация, стиль — с объяснением каждой правки
Спросить за 10 ₽Источники: WordPress REST API Handbook: Adding Custom Endpoints, WordPress REST API Handbook: Authentication
Частые вопросы
Нужно ли кешировать REST-ответ на CDN?
Транзиенты WordPress гарантируют кеш вне базы данных?
Почему endpoint медленный, хотя ответ уже закеширован?
Как понять, что проблему вызывает истечение кеша?
Можно ли использовать один ключ кеша для всех пользователей?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.