Перейти к содержимому

Кэширование своей выборки - ключ, теги, сброс

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

Решение

Оборачиваем выборку в кэш:

use Bitrix\Main\Data\Cache;
$cache = Cache::createInstance();
$key = 'top_products_' . $sectionId . '_' . $count; // ключ из значимых параметров
if ($cache->initCache(3600, $key, '/custom/catalog')) {
$items = $cache->getVars()['items'];
} elseif ($cache->startDataCache()) {
$items = fetchTopProducts($sectionId, $count); // сам запрос к базе
$cache->endDataCache(['items' => $items]);
}

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

Собираем ключ из всех значимых параметров:

$key = md5(serialize([
'section' => $sectionId,
'count' => $count,
'groups' => $USER->GetUserGroupArray(), // цены зависят от групп покупателя
'site' => SITE_ID,
'page' => (int)($_REQUEST['PAGEN_1'] ?? 1), // и номер страницы навигации
]));

В ключ входит всё, что меняет результат: раздел, отбор, язык, сайт и права текущего посетителя. Забытый параметр означает, что первый зашедший наполняет кэш своими данными, а остальные видят их вместо своих.

Привязываем кэш к данным тегами:

$taggedCache = \Bitrix\Main\Application::getInstance()->getTaggedCache();
$taggedCache->startTagCache('/custom/catalog');
$taggedCache->registerTag('iblock_id_5'); // кэш сбросится при правке элемента
$taggedCache->endTagCache();

Тег связывает кэш с инфоблоком, и правка любого его элемента сбрасывает кэш сама. Это и есть управляемый кэш: время жизни можно ставить долгим, потому что устаревать ему не дадут.

Сбрасываем свой кэш вручную:

$cache = Cache::createInstance();
$cache->cleanDir('/custom/catalog'); // весь каталог своего кэша
$cache->clean($key, '/custom/catalog'); // либо один ключ, если известен
BXClearCache(true, '/custom/catalog'); // то же самое старым вызовом

Ручной сброс нужен там, где данные меняются мимо платформы: после обмена, после массовой правки скриптом, после смены настроек. Тег о таких изменениях не узнает.

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

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

Кэш внутри цикла попросту бессмыслен: обёртка вокруг элемента даёт сотню файлов кэша вместо одного. Кэшируют целую выборку, а не отдельные её строки.

Типичные проблемы

Посетители видят чужие данные.

В ключ кэша не вошли группы пользователя или текущий сайт установки. Первый зашедший наполнил кэш своими данными, а все остальные читают их.

Правка товара не видна на витрине.

Свой кэш не привязан тегом к нужному инфоблоку. Без тега он живёт до конца своего времени жизни.

После обмена данные остались старыми.

Обмен меняет данные напрямую, минуя события самой платформы. Такой кэш сбрасывают вручную по завершении сеанса обмена.

Кэш занял гигабайты на диске.

Кэш собирается прямо внутри цикла по элементам. На каждый элемент создаётся свой файл кэша вместо одного на всю выборку.

Кэш не создаётся вовсе.

Кэширование выключено в настройках сайта либо каталог кэша закрыт для записи. Оба случая проверяются правами на каталог кэша.

Частые вопросы

Какое время жизни ставить?

С тегами - долгое, часы и сутки: сброс придёт от данных. Без тегов - столько, сколько данные допустимо показывать устаревшими.

Чем это отличается от кэша компонента?

Ничем по сути: компонент делает то же самое внутри себя. Свой кэш нужен коду вне компонентов.

Можно ли кэшировать в память вместо файлов?

Да, платформа умеет хранить кэш во внешних хранилищах. Настройка общая для сайта, код при этом не меняется.

Как посмотреть, что попало в кэш?

Открыть файл кэша в его каталоге: он читаемый. Это же лучший способ найти забытый параметр ключа.

Смежное

Первоисточник