1. Введение

Данная статья — это не научный прорыв, а лишь помощник, чтобы быстрее понять, как работает стандартный функционал в Bitrix.

Давайте представим, что в разделе каталога у нас 150 запросов к БД. Вроде бы немного при условии, если в один момент обращение к разделу происходит одним пользователем?

При одновременном обращении к разделу 200-т пользователей количество запросов равняется 200 * 150 = 30 000

Кеширование помогает снизить нагрузку на БД и сервер в целом.

Не судите за то, что я использую старое ядро в примере. Суть данной статьи показать, как это работает и потребности темы полностью покрываются.

2. Простое кеширование

//CPhpCache - класс для кеширования PHP переменных и HTML результата выполнения скрипта.
CModule::IncludeModule("main");

$arFilter = array(
    "IBLOCK_ID" => 17,
    "ACTIVE" => "Y",
    "GLOBAL_ACTIVE" => "Y",
);
$obCache = new CPHPCache();
/** 
Первый аргумент отвечает за время жизни кеша 
Второй аргумент - это хеш кеша. Например если в двух компонентах одинаковые запросы, то и кеш у них будет общий. Достаточно набрать кеш в одном компоненте.
Третий аргумент - это место хранения кеша. Путь не относительно корня сайта, а относительно папки с кешем. Для компонента каталог путь такой - /iblock/catalog
/
if($obCache->InitCache(36000, serialize($arFilter), "/iblock/catalog"))
{
   //Если кеш существует, то его результат сразу будет выдан и не надо выполнять код с запросами к БД
   $arCurSection = $obCache->GetVars();
}else{   //Если кеша нет, то выполнится код и сформируется кеш. В дальнейшем будет отдаваться переменная из кеша, а не выполняться этот код
   $obCache->StartDataCache();
   $arCurSection = array();
   $dbRes = CIBlockSection::GetList(array(), $arFilter, false, array("ID"));
   if(!$arCurSection = $dbRes->GetNext()){
   $arCurSection = array();
   }
   //$arCurSection - передаем в кеш переменную с полученными в коде значениями
   $obCache->EndDataCache($arCurSection);
}

Результат выполнения кода — это переменная $arCurSection со значениями полученными из кеша или запросов к БД.

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

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

Для того, чтобы решить проблему описанную в пункте 2, надо почистить директорию с кешем /iblock/catalog (путь не относительно корня сайта, а относительно папки с кешем) в момент добавления, изменения, удаления элементов инфоблока и связанных с ним сущностей, которые выводит наш компонент.

Для того, чтобы не изобретать «городушки» для сброса кеша при изменениях, был придуман тегированный кеш.

Для того, чтобы месту хранения кеша присвоить кеш используем это:

/** 
/iblock/catalog - место хранения кеша
"iblock_id_17" - тег для места хранения кеша
/
global $CACHE_MANAGER;
$CACHE_MANAGER->StartTagCache("/iblock/catalog");
$CACHE_MANAGER->RegisterTag("iblock_id_17");
$CACHE_MANAGER->EndTagCache();

Сброс кеша по тегу можно осуществить следующим способом:

/** 
"iblock_id_17" - тег для места хранения кеша
/
global $CACHE_MANAGER;
$CACHE_MANAGER->ClearByTag("iblock_id_17");

В итоге нам нужно лишь в нужный момент (навесить на события) сделать сброс кеша по тегу.

Например, в стандартных компонентах, использующих инфоблок, используется тег вида «iblock_id_17» и по этому тегу вызывается метод сброса кеша, который вызывается в методах добавления, изменения, удаления элемента инфоблока.

CModule::IncludeModule("iblock");
CIBlock::clearIblockTagCache($zr['IBLOCK_ID']);

Метод из ядра битрикс использующий ClearByTag:

//\bitrix\modules\iblock\classes\general\iblock.php
public static function clearIblockTagCache($iblock_id)
{
   global $CACHE_MANAGER;
   $iblock_id = (int)$iblock_id;
   if (defined("BX_COMP_MANAGED_CACHE") && $iblock_id > 0 && self::''isEnabledClearTagCache''())
  $CACHE_MANAGER->ClearByTag('iblock_id_'.$iblock_id);
}

4. Пример нестандартного использования кеша в каталоге

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

Косяк стандартного решения — при изменении какого-либо элемента сбрасывается весь кеш (элементы, разделы).

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

Тут единственная трудность в том, что бы хорошенечко подумать, в каких местах стоит так сделать.

5. Заключение

Смысл статьи не в научном открытии или какой-то доселе неведомой технологии, а демонстрации простоты решений.

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

Если у вас есть примеры, как можно использовать данный стандартный функционал, то пишите комментарии. Если есть примеры нестандартных решений — делитесь опытом.