Кэширование в PHP: Redis, Memcached и встроенные решения

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Кэширование в PHP: Redis, Memcached и встроенные решения — ускорение веб-приложений

Каждый разработчик PHP сталкивается с проблемой производительности: база данных отвечает медленно, страницы грузятся долго, а сервер задыхается под нагрузкой. Решение этих проблем лежит в грамотном кэшировании. В этой статье мы разберем три основных подхода к кэшированию в PHP: встроенные механизмы (APCu, OpCache), внешние серверы Memcached и Redis. Вы узнаете, когда какой инструмент выбрать, и получите готовые примеры кода для внедрения.

1. Встроенные решения: OpCache и APCu

Начнем с самого простого — кэширования на уровне PHP-движка. Здесь выделяют два ключевых компонента.

1.1. OpCache (PHP opcode cache)

OpCache встроен в PHP начиная с версии 5.5. Он кэширует скомпилированный байт-код (opcode) PHP-скриптов. Без него каждый запрос заново парсит и компилирует исходный код — это пустая трата ресурсов. Включение OpCache дает прирост скорости до 30-50% без единой строчки кода.

Настройка в php.ini:

opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60

1.2. APCu (Alternative PHP Cache user)

APCu — это кэш для пользовательских данных (переменных, результатов вычислений). Он работает в оперативной памяти и идеально подходит для хранения небольших, часто запрашиваемых данных: конфигураций, переводов, результатов простых SQL-запросов.

Пример работы с APCu:

<?php
// Сохраняем данные в кэш на 300 секунд
apcu_store('site_config', $config, 300);

// Получаем данные из кэша
$cached = apcu_fetch('site_config');
if ($cached === false) {
    // Данных нет — загружаем и сохраняем
    $cached = loadConfigFromDB();
    apcu_store('site_config', $cached, 300);
}

// Удаляем ключ
apcu_delete('site_config');
?>

Плюсы: не требует внешних сервисов, прост в настройке, минимальная задержка. Минусы: работает только на одном сервере, данные теряются при перезапуске PHP-FPM.

2. Memcached — распределенный кэш простых данных

Memcached — это высокопроизводительная распределенная система кэширования в оперативной памяти. Она идеальна для хранения простых пар "ключ-значение" и сессий. В отличие от APCu, Memcached работает как отдельный сервер и может быть общим для нескольких веб-серверов.

Установка расширения: pecl install memcached

Пример подключения и работы:

<?php
$memcached = new Memcached();
$memcached->addServer('localhost', 11211);

// Установка с TTL (time to live) 600 секунд
$memcached->set('user_123_profile', $profileData, 600);

// Получение
$profile = $memcached->get('user_123_profile');
if ($memcached->getResultCode() === Memcached::RES_NOTFOUND) {
    // Кэш промах — загружаем из БД
    $profile = getUserProfileFromDB(123);
    $memcached->set('user_123_profile', $profile, 600);
}

// Кэширование сессий (настройка в php.ini)
// session.save_handler = memcached
// session.save_path = "localhost:11211"
?>

Когда использовать Memcached:

  • Кэширование результатов SQL-запросов (списки товаров, категории)
  • Хранение сессий пользователей в распределенной среде
  • Кэширование HTML-блоков (например, меню или подвал)

Ограничения: нет встроенных структур данных (только строки), максимальный размер значения 1 МБ (можно увеличить), нет персистентности — при перезапуске сервера кэш очищается.

3. Redis — продвинутый кэш с структурами данных

Redis — это не просто кэш, а полноценное хранилище данных в памяти с поддержкой сложных типов: списки, множества, хэши, сортированные множества. Он поддерживает персистентность (сохранение на диск), транзакции, pub/sub и TTL.

Установка через Composer (predis/predis) или pecl (phpredis):

Пример с использованием phpredis:

<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('password'); // если установлен пароль

// Хэши — идеально для объектов
$redis->hSet('user:456', 'name', 'Иван');
$redis->hSet('user:456', 'email', 'ivan@example.com');
$user = $redis->hGetAll('user:456');

// Списки — для очередей задач
$redis->lPush('task_queue', 'send_email_to_user_456');
$task = $redis->rPop('task_queue');

// Множества — для уникальных значений
$redis->sAdd('online_users', 'user_456');
$isOnline = $redis->sIsMember('online_users', 'user_456');

// Кэширование с TTL
$redis->setex('article:789', 3600, $articleContent);

// Инкремент — для счетчиков
$redis->incr('page_views:home');
?>

Продвинутый пример: кэширование с блокировкой (Mutex)

<?php
function getExpensiveData($redis, $key, $ttl = 600) {
    $data = $redis->get($key);
    if ($data !== false) {
        return unserialize($data);
    }

    // Блокировка для предотвращения "cache stampede"
    $lockKey = $key . ':lock';
    if ($redis->setnx($lockKey, 1)) {
        $redis->expire($lockKey, 10); // Таймаут блокировки

        // Дорогостоящее вычисление
        $data = computeExpensiveData();
        $redis->setex($key, $ttl, serialize($data));

        $redis->del($lockKey);
        return $data;
    }

    // Если блокировка занята — ждем 50 мс и пробуем снова
    usleep(50000);
    return getExpensiveData($redis, $key, $ttl);
}
?>

Когда выбирать Redis:

  • Сложные структуры

Блоги

Рекомендаций по книгам