Главная » Разработка Битрикс » D7 » Bitrix\Main\Data\Cache — кеширование в Битрикс D7

Bitrix\Main\Data\Cache — кеширование в Битрикс D7

Схема кеширования в Битрикс D7: при попадании в кеш данные берутся готовыми, иначе пересчитываются и сохраняются

Кеширование в компонентах включается галочкой, а вот собственный код кешируется вручную. Тяжёлая выборка, обращение к внешнему API, сложный расчёт — всё это должно выполняться раз в час, а не при каждом открытии страницы.

В D7 для этого есть Bitrix\Main\Data\Cache. Разберём базовый шаблон использования, работу с тегированным кешем и типичные ошибки, из-за которых кеш либо не работает, либо отдаёт устаревшие данные.

Базовый шаблон

Конструкция всегда одинаковая — три метода и условие:

<?php

use Bitrix\Main\Data\Cache;

$cache     = Cache::createInstance();
$cacheTime = 3600;                       // секунд
$cacheId   = 'catalog_top_' . $sectionId;
$cachePath = '/catalog/top/';

if ($cache->initCache($cacheTime, $cacheId, $cachePath)) {

    // кеш есть и не устарел — берём готовое
    $items = $cache->getVars()['items'];

} elseif ($cache->startDataCache()) {

    // кеша нет — считаем
    $items = getExpensiveData($sectionId);

    // и сохраняем
    $cache->endDataCache(['items' => $items]);
}

Разберём параметры:

ПараметрНазначение
Время жизни Сколько секунд кеш считается актуальным
Идентификатор Уникальный ключ. Обязан включать все параметры выборки
Путь Подпапка в хранилище кеша — упрощает выборочную очистку

Идентификатор — главное место ошибок

Ключ кеша должен зависеть от всего, что влияет на результат. Если выборка зависит от раздела, языка и группы пользователя, все три параметра обязаны попасть в ключ.

Плохо:

<?php
$cacheId = 'catalog_items';  // один кеш на все разделы

Хорошо:

<?php

$cacheId = md5(serialize([
    'section'  => $sectionId,
    'page'     => $page,
    'groups'   => $USER->GetUserGroupArray(),
    'lang'     => LANGUAGE_ID,
]));

Забытый параметр приводит к самому неприятному классу багов: часть пользователей видит чужие данные. Особенно опасно забыть группы пользователя, когда от них зависят цены или доступность товаров.

Обратная крайность тоже вредна: если добавить в ключ что-то уникальное для каждого посетителя — например, идентификатор сессии, — кеш перестанет попадать вообще, а хранилище будет забиваться мусором.

Нужна помощь с Битрикс?





    Тегированный кеш

    Обычный кеш живёт до истечения времени. Но если товар отредактировали, ждать час бессмысленно — данные уже устарели.

    Тегированный кеш решает это: кеш помечается тегом, а при изменении данных все записи с этим тегом сбрасываются.

    <?php
    
    use Bitrix\Main\Data\Cache;
    use Bitrix\Main\Application;
    
    $cache       = Cache::createInstance();
    $taggedCache = Application::getInstance()->getTaggedCache();
    
    if ($cache->initCache(3600, $cacheId, $cachePath)) {
    
        $items = $cache->getVars()['items'];
    
    } elseif ($cache->startDataCache()) {
    
        $taggedCache->startTagCache($cachePath);
        $taggedCache->registerTag('iblock_id_' . $iblockId);
    
        $items = getExpensiveData();
    
        $taggedCache->endTagCache();
        $cache->endDataCache(['items' => $items]);
    }

    Тег iblock_id_{ID} — стандартный: Битрикс сбрасывает его сам при изменении любого элемента инфоблока. Свои теги можно сбрасывать вручную:

    <?php
    
    $taggedCache->clearByTag('my_custom_tag');

    Важное условие: тегированный кеш должен быть включён в настройках главного модуля. Если он выключен, регистрация тегов ничего не делает, и кеш будет жить до истечения времени.

    Очистка кеша

    <?php
    
    // очистить конкретную запись
    $cache->clean($cacheId, $cachePath);
    
    // очистить всю подпапку
    $cache->cleanDir($cachePath);

    Именно ради выборочной очистки стоит использовать осмысленные пути: /catalog/top/ удобнее, чем всё в корне хранилища.

    Что кешировать, а что нет

    ОперацияКешировать
    Тяжёлая выборка из базыДа
    Запрос к внешнему APIДа, обязательно
    Построение дерева разделовДа
    Сложный расчёт по многим записямДа
    Данные корзины пользователяНет
    Персональные данныеНет
    Простой запрос по первичному ключуОбычно не нужно
    Курс валют из внешнего сервисаДа, с коротким временем

    Особый случай — внешние API. Кеш здесь не только ускоряет, но и защищает: если сторонний сервис лёг, сайт продолжит работать на закешированных данных до истечения срока.

    Где физически лежит кеш

    По умолчанию — в файлах в папке /bitrix/cache/. На нагруженных проектах файловое хранилище становится узким местом, и его переносят в память:

    • Memcached — быстрый, простой, подходит большинству проектов;
    • Redis — умеет больше, устойчивее к перезапускам.

    Что важно: код при этом не меняется. Cache::createInstance() сам использует настроенное хранилище. Настройка описана в статьях Настройка Memcached в Битрикс и Redis для Битрикс.

    Отладка

    Проверить, попадает ли код в кеш, проще всего логированием ветки пересчёта:

    <?php
    
    if ($cache->initCache($cacheTime, $cacheId, $cachePath)) {
        $items = $cache->getVars()['items'];
    } elseif ($cache->startDataCache()) {
    
        \Bitrix\Main\Diag\Debug::writeToFile(
            'кеш пересчитан: ' . $cacheId,
            'CACHE',
            '/local/logs/cache.log'
        );
    
        $items = getExpensiveData();
        $cache->endDataCache(['items' => $items]);
    }

    Если в логе запись появляется при каждом обновлении страницы — кеш не работает. Обычно причина в том, что идентификатор содержит что-то уникальное для каждого запроса.

    Частые ошибки

    • Неполный идентификатор. Пользователи видят данные из чужого контекста.
    • Уникальный идентификатор на каждый запрос. Кеш не попадает никогда, хранилище растёт.
    • Забытый endDataCache(). Результат не сохраняется, расчёт идёт каждый раз.
    • Кеширование персональных данных. Самая опасная ошибка: один пользователь получает информацию другого.
    • Слишком долгое время жизни без тегов. Контент обновили, а сайт сутки показывает старое.
    • Регистрация тегов при выключенном тегированном кеше. Работает как обычный кеш, а разработчик ждёт автоматического сброса.

    Итог

    Bitrix\Main\Data\Cache кеширует результаты собственного кода: тяжёлые выборки, обращения к внешним сервисам и сложные расчёты. Схема неизменна — initCache, startDataCache, endDataCache.

    Ключевое требование — правильный идентификатор: в него должны входить все параметры, влияющие на результат, включая группы пользователя. А чтобы кеш сбрасывался при изменении данных, а не по таймеру, используйте тегированный кеш — при условии, что он включён в настройках модуля.

    Нужна помощь с Битрикс?

    Исправим ошибку, доработаем сайт, ускорим Битрикс или поможем разобраться с проблемой.

    Услуги
    База знаний