Система кешування у WordPress являє собою багаторівневу архітектуру, розділену на runtime-пам'ять процесу, абстракцію тимчасових даних (Transients API) та персистентне об'єктне сховище (Persistent Object Cache).
Runtime Object Cache (WP_Object_Cache): за замовчуванням вбудований у ядро механізм кешує об'єкти в оперативній пам'яті PHP-процесу (static array). Термін життя цього кешу обмежений життєвим циклом одного HTTP-запиту. Він запобігає повторним SQL-запитам усередині одного скрипта (наприклад, повторний виклик get_post(42) не звертається до СКБД), але повністю очищується при завершенні запиту.
Drop-in персистентного кешу (object-cache.php): розміщення файлу wp-content/object-cache.php перевизначає стандартний клас WP_Object_Cache. У корпоративних інфраструктурах 2026 року в якості бекенду використовуються розподілені In-Memory СКБД Redis 7.4+ або Valkey. Персистентний об'єктний кеш зберігає серіалізовані структури даних між незалежними HTTP-запитами, знижуючи кількість запитів до MySQL із сотень до одиниць на сторінку.
Transients API: історичний інтерфейс ядра для збереження тимчасових даних зі встановленим терміном життя (TTL):
set_transient($key, $value, $expiration)get_transient($key)delete_transient($key)Архітектурна розвилка Transients API:
*_transient() прозоро перенаправляються у wp_cache_*(), використовуючи групу transient. Дані осідають у Redis з нативним механізмом закінчення ключів (EXPIRE).wp_options у вигляді двох незалежних рядків: _transient_{key} та _transient_timeout_{key}. Якщо термін життя не вказано ($expiration = 0), транзієнт позначається прапорцем autoload = 'yes'. Це призводить до катастрофічного розростання (bloat) таблиці wp_options, деградації опції alloptions та вимивання оперативної пам'яті сервера при кожному старті ядра.Критичним викликом highload-архітектури є ефект собачої упряжки (Cache Stampede / Dogpile Effect / Thundering Herd): момент, коли гарячий ключ із мільйоном запитів на хвилину закінчується, і тисячі паралельних робочих процесів PHP одночасно отримують «cache miss» та атакують MySQL однаковими важкими обчисленнями. Для ліквідації цієї проблеми застосовуються розподілені м'ютекси (wp_cache_add) та алгоритм превентивного ймовірнісного перерахунку (XFetch).
Порівняння поведінки системи при закінченні терміну гарячого ключа: класичний колапс (Thundering Herd) проти захищеного м'ютекса (Distributed Mutex Gate):
КАТАСТРОФА: THUNDERING HERD (Без м'ютекса)
=================================================================================
Ключ закінчився в Redis!
Запит 1 (Miss) ----+
Запит 2 (Miss) ----|---> 10 000 паралельних важких SQL-запитів до MySQL!
Запит 3 (Miss) ----| [Результат: 100% CPU, вичерпання з'єднань, 504 Gateway Timeout]
Запит N (Miss) ----+
АРХІТЕКТУРА ENTERPRISE: ATOMIC MUTEX + STALE SERVE
=================================================================================
Ключ закінчився в Redis!
Запит 1 (Miss) ---> Намагається взяти м'ютекс (wp_cache_add / SETNX) -> УСПІХ!
|---> Виконує важкий SQL (1 потік)
v
Оновлює Redis і звільняє м'ютекс
Запит 2 (Miss) ---> Намагається взяти м'ютекс -> ЗАЙНЯТО!
|---> Повертає застарілі дані (Stale Cache) або чекає 50 мс
Запит 3 (Miss) ---> Намагається взяти м'ютекс -> ЗАЙНЯТО! -> Повертає Stale CacheМеханізм підміни вбудованого неперсистентного кешу ядра на зовнішнє розподілене сховище (Redis/Valkey) через drop-in файл, що забезпечує збереження об'єктів між HTTP-запитами.
Критичне засмічення таблиці wp_options мільйонами рядків застарілих транзієнтів при відсутності Redis, що призводить до роздування кешу alloptions та різкого зростання TTFB при старті ядра WordPress.
Каскадне перевантаження бази даних, що виникає при одночасному зверненні багатьох паралельних запитів до щойно простроченого ключа кешу з важким алгоритмом генерації.
Алгоритм превентивної фонової регенерації кешу, при якому ймовірність перерахунку значення зростає в міру наближення часу закінчення ключа (TTL), повністю запобігаючи лавиноподібним промахам кешу.
Використання атомарної операції запису wp_cache_add (аналог Redis SETNX), що гарантує, що рівно один робочий процес отримує право на регенерацію важкого набору даних.
Спроба вилучення об'єкта з Redis через wp_cache_get(). Якщо ключ валідний, дані повертаються клієнту за 0.5–1 мс.
Розрахунок ймовірності наближення кінця TTL. Якщо обчислення потрапляє в межу дельти, один із вхідних потоків ініціює асинхронний перерахунок до фактичного закінчення ключа.
При промаху кешу потік намагається виконати wp_cache_add(lock_key, 1, group, 10). Функція завершиться успіхом тільки для першого процесу в мілісекунду.
Переможний потік виконує важкий SQL або запит до зовнішнього API. Усі інші потоки миттєво віддають злегка застарілий кеш (Stale-While-Revalidate).
Переможний потік записує свіжі дані через wp_cache_set(), оновлює мета-таймстемп та видаляє ключ блокування.
wp_cache_incr() у Redis замість виконання важких UPDATE wp_postmeta SET meta_value = meta_value + 1 при кожному візиті.WP_CACHE_KEY_SALT у wp-config.php для виключення колізій ключів між staging та production на одному Redis-інстансі.При проєктуванні кеш-стратегії важливо розрізняти роботу з БД та роботу з пам'яттю:
Виклик функції wp_cache_flush() очищує абсолютно всю базу даних у Redis. У наступну ж мілісекунду сотні вхідних HTTP-запитів виявляють абсолютно порожній кеш. Навантаження на СКБД MySQL миттєво зростає в 50–100 разів: сервер іде в глибокий свопінг, вичерпує пул max_connections і падає з помилкою «Error establishing a database connection».
Стандарт 2026 року забороняє глобальне скидання кешу. Замість цього застосовується Key Versioning (версіонування ключів груп):
// Інвалідація групи без очищення Redis: просто інкрементуємо версію групи
$version = wp_cache_incr('group_version', 1, 'catalog_meta');
// Усі подальші ключі будуються як "catalog_items:v{$version}"Нижче наведено відмовостійкий менеджер кешування на PHP 8.4+, що реалізує захист від Cache Stampede через розподілений м'ютекс, версіонування ключів груп та безпечну дедуплікацію.
<?php
declare(strict_types=1);
namespace AgenticLab\Performance;
use Closure;
/**
* Enterprise Resilient Cache Manager.
*
* Відмовостійкий менеджер кешу із захистом від Thundering Herd / Dogpile ефекту.
*
* Author: Artur Yusupov (Fullstack Agentic Lab)
*/
final class AgenticResilientCache {
private const string LOCK_GROUP = 'agentic_cache_locks';
private const int DEFAULT_LOCK_TTL = 15; // Секунди блокування на час розрахунку
/**
* Виконання важкої операції з гарантією захисту від Cache Stampede.
*
* @template T
* @param string $key Ключ кешу
* @param string $group Група кешу
* @param int $ttl Час життя в секундах
* @param Closure(): T $compute Функція обчислення даних при промаху
* @return T
*/
public static function remember(
string $key,
string $group,
int $ttl,
Closure $compute
): mixed {
$versioned_key = self::build_versioned_key($key, $group);
$found = false;
/** @var mixed $cached */
$cached = wp_cache_get($versioned_key, $group, false, $found);
if ($found && $cached !== false) {
/** @var T */
return $cached;
}
// Кешу немає. Намагаємося захопити атомарний розподілений м'ютекс
$lock_key = "lock:{$versioned_key}";
$is_locked = !wp_cache_add($lock_key, 1, self::LOCK_GROUP, self::DEFAULT_LOCK_TTL);
if ($is_locked) {
// Інший робочий процес уже виконує розрахунок.
// Намагаємося повернути застарілий кеш (Stale-While-Revalidate)
$stale_key = "stale:{$versioned_key}";
$stale_found = false;
$stale_data = wp_cache_get($stale_key, $group, false, $stale_found);
if ($stale_found && $stale_data !== false) {
/** @var T */
return $stale_data;
}
// Якщо застарілого кешу немає, чекаємо 50 мс і пробуємо прочитати знову
usleep(50000);
$retry_cached = wp_cache_get($versioned_key, $group, false, $found);
if ($found && $retry_cached !== false) {
/** @var T */
return $retry_cached;
}
}
// Ми захопили м'ютекс або очікування минуло: виконуємо обчислення
try {
/** @var T $result */
$result = $compute();
// Зберігаємо свіжі дані
wp_cache_set($versioned_key, $result, $group, $ttl);
// Зберігаємо запасну stale-копію з подвоєним TTL
wp_cache_set("stale:{$versioned_key}", $result, $group, $ttl * 2);
return $result;
} finally {
// Обов'язково звільняємо м'ютекс блокування
wp_cache_delete($lock_key, self::LOCK_GROUP);
}
}
/**
* Миттєва інвалідація всієї групи кешу без виклику небезпечного wp_cache_flush().
*/
public static function invalidate_group(string $group): void {
$version_key = "version:{$group}";
$current_version = (int)wp_cache_get($version_key, 'group_versions');
if ($current_version === 0) {
wp_cache_set($version_key, 2, 'group_versions', 0);
} else {
wp_cache_incr($version_key, 1, 'group_versions');
}
}
/**
* Побудова ключа з урахуванням поточної версії групи.
*/
private static function build_versioned_key(string $key, string $group): string {
$version_key = "version:{$group}";
$version = wp_cache_get($version_key, 'group_versions');
if ($version === false) {
$version = 1;
wp_cache_set($version_key, 1, 'group_versions', 0);
}
return "v{$version}:{$key}";
}
}
Розгортання інстансу Redis 7.4+ з налаштуванням ліміту пам'яті maxmemory 2gb та політики витіснення ключів maxmemory-policy allkeys-lru.
Гарантує, що Redis не впаде при переповненні оперативної пам'яті.
Встановлення перевіреного клієнтського драйвера (наприклад, Redis Object Cache Pro) у каталог wp-content/object-cache.php із підтримкою конектора PhpRedis.
Забезпечує продуктивність скомпільованого C-розширення.
Налаштування унікальної константи WP_CACHE_KEY_SALT, що об'єднує назву проєкту, середовище оточення та версію структури даних.
Повністю усуває ризик витоку даних між Staging та Production.
Виконання WP-CLI команди wp transient delete --expired та видалення осиротілих записів _transient_timeout_* з бази даних MySQL.
Звільняє мегабайти пам'яті в автозавантажуваному кеші alloptions.
Ефективна стратегія кешування в enterprise-рішеннях 2026 року на WordPress тримається на трьох стовпах:
object-cache.php з політикою пам'яті allkeys-lru.wp_cache_add) та алгоритмів ймовірнісного оновлення для важких ключів.wp_cache_flush() на користь версіонування ключів груп (Key Versioning).