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

Кеширование в 1С-Битрикс - автокеш, D7 Cache, тегированный кеш

В 1С-Битрикс несколько независимых механизмов кеширования, и их принято совмещать: каждый участок кешируется подходящим способом. Разберём все уровни, правила формирования ключей и главную проблему любого кеша - своевременный сброс.

Как это работает

Автокеширование компонентов. Штатные компоненты сохраняют результат в файлы и на повторных запросах не обращаются к базе вовсе. Режимы три: «Авто плюс управляемое» - обновление и по времени, и при изменении данных; «Кешировать» - только по времени жизни; «Не кешировать».

Обычный кеш не перестраивается при изменении данных и живёт заданное время. Подходит там, где допустима небольшая задержка актуальности. В новом коде для своих данных используют класс Bitrix\Main\Data\Cache, в старом встречается CPHPCache.

Управляемый кеш хранится отдельно и сбрасывается точечно по ключу или каталогу. Привязка к таблице ORM даёт автоматический сброс после добавления, изменения или удаления записи.

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

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

Для нового кода приоритет такой: Data\Cache, ManagedCache, TaggedCache. Классы CPHPCache и менеджер кеша из старого ядра - обёртки над тем же механизмом, они нужны для правки легаси. И общее правило: кешируют только производные данные, которые можно безопасно потерять и пересчитать.

Примеры

1. Свой кеш данных

use Bitrix\Main\Data\Cache;
$cache = Cache::createInstance();
$cacheTtl = 86400;
$cacheId = 'top_products_' . SITE_ID . '_' . $sectionId;
$cacheDir = '/catalog/top/' . substr(md5($sectionId), 0, 2);
if ($cache->initCache($cacheTtl, $cacheId, $cacheDir)) {
$vars = $cache->getVars();
$items = $vars['items'];
} elseif ($cache->startDataCache()) {
$items = $this->loadTopProducts($sectionId);
if (empty($items)) {
$cache->abortDataCache(); // не кешируем пустой результат
return [];
}
$cache->endDataCache(['items' => $items]);
}

Три правила, которые делают этот код правильным:

  • В идентификатор кеша включено всё, от чего зависит выборка. Разный вход под одним ключом - это испорченный кеш и трудноуловимые баги.
  • Кеш разложен по подпапкам. Одна общая папка на миллион файлов приводит к массовому сбросу при обновлении и переполняет акселератор.
  • При ошибке или пустом результате вызывается отмена, а не сохранение частичных данных.

Время жизни ставьте длинным. Час - это обычно слишком мало: кеш будет пересоздаваться чаще, чем приносить пользу. Для управляемого и тегированного кеша нормально ставить неделю и больше, потому что сбросом управляет не время, а события.

2. Кеш компонента

if ($this->startResultCache()) {
$this->arResult['ITEMS'] = $this->loadItems();
if (empty($this->arResult['ITEMS'])) {
$this->abortResultCache();
return;
}
$this->SetResultCacheKeys(['ITEMS']); // в кеш попадёт только это
$this->includeComponentTemplate();
}

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

3. Управляемый кеш

$managedCache = \Bitrix\Main\Application::getInstance()->getManagedCache();
if ($managedCache->read(86400 * 30, $cacheKey, 'orm_b_example_item')) {
$data = $managedCache->get($cacheKey);
} else {
$data = $this->calculate();
$managedCache->set($cacheKey, $data);
}

Порядок здесь строгий: сначала чтение, потом получение или запись. Это не независимое key-value хранилище, и вызов записи без предшествующего чтения некорректен. Третий параметр связывает кеш с таблицей ORM - тогда он сбросится автоматически при изменении данных этой таблицы.

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

$taggedCache = \Bitrix\Main\Application::getInstance()->getTaggedCache();
$taggedCache->startTagCache($cacheDir);
$taggedCache->registerTag('my_catalog_prices');
$taggedCache->endTagCache();
// при изменении данных
$taggedCache->clearByTag('my_catalog_prices');

Для инфоблоков теги регистрируются автоматически - но только при включённом управляемом кеше. Без константы BX_COMP_MANAGED_CACHE регистрация и сброс тегов молча ничего не делают, и это самая частая причина жалобы «тегированный кеш не работает».

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

\CIBlock::disableTagCache($iblockId);
// массовая загрузка
\CIBlock::enableTagCache($iblockId);
\CIBlock::clearIblockTagCache($iblockId);

Справочник API

APIНазначениеОсобенности
Data\Cache::createInstance()свой кеш данныхосновной способ в новом коде
initCache() / getVars()чтение из кеша
startDataCache() / endDataCache()запись в кеш
abortDataCache()отмена записипри ошибке или пустом результате
CPHPCacheлегаси-аналогтолько для правки старого кода
startResultCache() / abortResultCache()кеш компонентавнутри - подключение шаблона
SetResultCacheKeys()ограничение состава кешабез него кешируется весь результат
getManagedCache()управляемый кешпорядок: read, затем get или set
каталог orm_<таблица>связь кеша с таблицейдаёт автосброс при изменении данных
getTaggedCache()тегированный кешstartTagCache, registerTag, endTagCache
clearByTag()сброс по тегу
BX_COMP_MANAGED_CACHEвключение управляемого кешабез неё теги не работают
disableTagCache() / enableTagCache()отключение тегов на время импортаплюс явный сброс после
sid кешаразделение кеша между сайтамиуникальный суффикс на сайт или язык

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

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

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

Сохранение частичного результата после ошибки. В кеш попадает невалидное состояние, и оно живёт до истечения времени жизни. Нужна отмена.

Тегированный кеш инфоблоков «не работает». Не включён управляемый кеш.

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

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

Ручное удаление файлов кеша. Правильный способ - очистка из админки или методы платформы.

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

Какой кеш выбрать для своей выборки?

Если данные меняются редко и допустима задержка - обычный кеш через Data\Cache с длинным временем жизни. Если нужен мгновенный сброс при изменении - управляемый кеш с привязкой к таблице ORM или тегированный кеш с доменным тегом. Если данные меняются постоянно и должны быть всегда актуальными, кеш вообще не нужен: он будет сбрасываться чаще, чем использоваться.

Что должно входить в идентификатор кеша?

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

Почему тегированный кеш не сбрасывается?

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

Почему файлы кеша занимают гигабайты?

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

Связанные темы

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