Объектный кэш Redis для WordPress
Объектный кэш Redis для WordPress
Объектный кэш — второй уровень кэширования после кэша страниц. Если кэш страниц сохраняет готовый HTML, то объектный кэш хранит в ОЗУ результаты SQL-запросов: опции, термины, транзиенты, произвольные данные плагинов. Каждый просмотр страницы перестаёт гонять эти запросы в MySQL.
Ключевое свойство, из-за которого он стоит особняком: объектный кэш кэширует данные, а не HTML. Значит он не нарушает DONOTCACHEPAGE — заголовок «не кэшировать страницу» относится к страничному кэшу, а данные в ОЗУ кэшировать можно всегда. Это единственный способ ускорить сайт, где стоит обязательный экран согласия или другой HTML-гейт.
Замеры A/B на живом сайте
Сайт: WordPress с ~2 300 записей и экраном согласия (страничное кэширование отключено), VPS с nginx + PHP 8.5 + MySQL локально, Redis 7.x на том же сервере. Методика: ab -n 300 -c 10 + серия одиночных запросов, объектный кэш включался/выключался штатной командой плагина.
| Параметр | Без объектного кэша | С Redis |
|---|---|---|
| Запросов/сек | 5,2 | 6,0 (+15 %) |
| Средний запрос (ab) | 1 913 мс | 1 659 мс |
| TTFB главной, одиночные | 0,18–0,23 с | 0,16–0,19 с |
| Ошибок | 0 | 0 |
Плюс контекст из серии замеров того же сайта: до всех оптимизаций (без BLC, с экраном согласия, без объектного кэша) — 1,28 запроса/сек; после отключения BLC — 5,2; после исправления двух тяжёлых мест кода (транслитерация через API и загрузка шрифтов) и с Redis — 6,0.
Второй сайт: замер на сайте №2
Повторил тот же эксперимент на втором сайте — 145 МБ база, ~9 300 записей, BLC недавно отключён, кэша страниц нет (рендер живьём 2,2–2,6 с). Переключение — перемещением дропина object-cache.php (тот же слот, другой механизм).
| Параметр | Без объектного кэша | С Redis (база 1) |
|---|---|---|
| Запросов/сек | 1,93 | 2,68 (+39 %) |
| Средний запрос (ab 200×10) | 5 175 мс | 3 731 мс |
| TTFB главной, одиночные | 2,19–2,57 с | 1,47–1,9 с |
+39 % RPS и −28 % времени среднего запроса — эффект заметнее, чем на первом сайте, потому что здесь SQL-запросов на просмотр больше (related posts, виджеты, счётчики просмотров).
Как читать эти цифры
- Одиночный запрос после всех исправлений рендерится за ~0,2 с, и объектный кэш меняет его слабо: MySQL на локальном NVMe и так быстр, оставшиеся 0,17–0,2 с — это исполнение PHP-кода.
- Разница проявляется под нагрузкой: без объектного кэша каждый запрос бьёт в MySQL сотнями запросов, и при 10 параллельных среднее время уже 1,9 с. Redis снимает часть этих запросов — потолок нагрузки выше.
- На тяжёлом сайте (много запросов опций/терминов на просмотр) выигрыш от объектного кэша заметно больше — это первое, что стоит включать после профилирования, если в топе SQL-запросы к опциям и терминам.
Установка на VPS с CloudPanel
Три части: сервер Redis, PHP-расширение, дропин в WordPress.
1. Сервер
sudo apt-get install redis-server
На моём сервере Redis 7.x уже стоял и был запущен. Проверить: redis-cli ping → PONG.
2. PHP-расширение
Для PHP 8.5 (CloudPanel): пакет php8.5-redis из репозитория панели. Проверка: php8.5 -m | grep redis.
3. WordPress
wp plugin install redis-cache --activate --path=/путь/к/сайту
wp redis enable --path=/путь/к/сайту
wp cache type --path=/путь/к/сайту # должно ответить Redis
wp redis enable создаёт дропин wp-content/object-cache.php. Константы в wp-config при локальном Redis необязательны (хост 127.0.0.1 по умолчанию), но для порядка можно задать:
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
Изоляция нескольких сайтов на одном Redis
По умолчанию все сайты на сервере делят один Redis — ключи с одинаковыми именами столкнутся (опции options, транзиенты разных сайтов перезапишут друг друга). Два способа изоляции:
- Разные базы Redis (индексы 0–15): в wp-config каждого сайта
define( 'WP_REDIS_DATABASE', 0 );, следующему сайту — 1, и так далее. Минус: индексов всего 16. - Соль ключей:
define( 'WP_CACHE_KEY_SALT', 'site1_' );— префикс в именах ключей. Баз неограниченно.
После включения полезно снять «слепок»: redis-cli dbsize — число ключей растёт, значит кэш наполняется.
Подводные камни
- Рестарт Redis = пустой кэш. Кэш в ОЗУ: после перезапуска первые запросы рендерятся живьём, пока кэш не наполнится. Для сайта с экраном согласия это ок (см. ниже), для магазина — учитывайте прогрев.
- eviction. При переполнении памяти Redis выкидывает ключи — задайте
maxmemoryс запасом и политику (например,allkeys-lru). - Плагины кэша страниц не конфликтуют с объектным кэшем — они про разное (HTML vs данные) и используют разные слоты:
advanced-cache.phpиobject-cache.php. - Внешний доступ. Слушайте Redis только на localhost (
bind 127.0.0.1), иначе открытый без пароля Redis — классическая дыра. - Если сайт под экраном согласия с персональными cookie в ответах — Redis-объектный кэш данных это не нарушение: кэшируются запросы к БД, а не HTML.
Холодная страница, попадания и срок жизни
Замер «холодной страницы»: полный сброс кэша → один запрос (гарантированный MISS) → ещё 5 запросов (гарантированные HIT). По 3 цикла на сайт.
| Сайт | Холодная (MISS), 3 замера | Тёплая (HIT), 5 замеров | Выигрыш тёплых |
|---|---|---|---|
| Сайт №1 | 0,24 / 0,26 / 0,35 с | 0,17–0,18 с | ~35 % |
| Сайт №2 | 2,37 / 2,54 / 2,87 с | 1,78–1,84 с | ~29 % |
Как происходит попадание в кэш. Плагин Redis Object Cache (Till Krüss, v3.0.0 на обоих сайтах) при активации кладёт дропин wp-content/object-cache.php. Дальше WordPress сам, прозрачно для плагинов и темы:
- первый запрос к любым данным (опции, термины, мета, произвольные вызовы
wp_cache_get) идёт в MySQL, результат сохраняется в Redis; - все повторные запросы тех же данных — из ОЗУ (~0,1–0,5 мс вместо 0,2–2 мс на запрос);
- при обновлении записи/комментария/опции соответствующие ключи инвалидируются автоматически.
На сколько живёт кэш. Основные ключи — бессрочно (TTL −1): опции, термины, связи, мета живут до инвалидации при обновлении контента, до рестарта Redis или вытеснения при переполнении памяти. Временные данные — по своему TTL (например, кэш файлов переводов — 1 час). Для сайта с экраном согласия это правильное поведение: данные кэшируются, HTML — нет, правило «не делить HTML между посетителями» не нарушается.
Ловушки
- Не совмещайте с другим кэш-плагином: оба претендуют на
wp-content/object-cache.php. - Кэш в ОЗУ: рестарт Redis сбрасывает его целиком — первые посетители после рестарта получают «холодные» рендеры (на первом сайте это +0,2 с, на втором +0,7–1 с к тёплому уровню).
- Несколько сайтов на одном Redis: разносите по базам (
WP_REDIS_DATABASE0–15) или соли ключей (WP_CACHE_KEY_SALT) — иначе опции и транзиенты разных сайтов столкнутся. - Внешний доступ. Слушайте только localhost: открытый без пароля Redis — классическая дыра.
wp config setможет падать на старых wp-config без стандартных якорей — константы вставляйте вручную перед$table_prefix.- Альтернативный бэкенд Memcached — рабочий: через плагин Memcached Redux (дропин копируется вручную, сам плагин не активируется). В одинаковом замере на первом сайте Redis дал +12 % RPS, Memcached +18 % — разница в пределах погрешности. Automattic-плагин «Memcached» по-прежнему не работает на PHP 8.5 без PECL-сборки старого расширения. Замеры и обе ловушки установки — в обзоре Memcached.
Статус на сервере (обновлено 2026-10-21): основной сайт на Memcached, Redis выведен
После сбоя дата-центра (ребут VPS с выборочной потерей файлов — пропали конфиг Redis и дропин object-cache.php) Redis был полностью починен (apt-get install --reinstall --force-confmiss + пересоздание /var/lib/redis), но владелец перевёл объектный кэш основного сайта на Memcached: memcached в автозапуске, дропин Memcached Redux на месте, Redis остановлен и не в автозапуске (конфиг и данные целы — вернуть можно одной командой systemctl enable --now redis-server + wp redis enable).
Пакеты при этом остались установленными: они являются жёсткими зависимостями пакета CloudPanel — попытка их purge (apt-get purge) вызывает pre-removal скрипт панели, который останавливает nginx и MySQL и запускает удаление всех сайтов с панели. Прерывание этой цепочки безопасно, но полное удаление пакетов вырвал бы панель вместе с сайтами.
Сайты работают штатно (все 4 — HTTP 200): основной ~0,2 с на просмотр (после исправлений кода), второй ~1,7–1,9 с, остальные — без изменений.
Выводы
- Объектный кэш — второй уровень после кэша страниц: ускоряет каждый рендер, снимает нагрузку с MySQL, работает при любом
DONOTCACHEPAGE. - На лёгком и уже быстром сайте выигрыш скромный (+15 % RPS под нагрузкой в моём замере) — зато потолок нагрузки растёт, и это самый безопасный вид кэширования для сайтов с гейтами и приватностью.
- На втором сайте (145 МБ, 9 300 записей) та же настройка дала +39 % RPS и −28 % времени среднего запроса — чем тяжелее SQL-нагрузка на просмотр, тем больше выигрыш.
- Ставится за 10 минут: сервер + расширение + один плагин + одна команда
wp redis enable. - Замерять A/B честно: плагин кэша самовосстанавливает свой дропин после удаления — «отключение» только штатным методом плагина, иначе сравнение получится фиктивным (как вышло у меня в первой попытке).
- «Холодная» страница после сброса кэша — это полный рендер; на первом сайте 0,24–0,35 с после всех исправлений кода, на втором 2,4–2,9 с. Прогрев кэша по sitemap убирает и эту разницу для посетителей.
