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{   //Если кеша нет, то выполнится код и сформируется кеш. В дальнейшем будет отдаваться переменная из кеша, а не выполняться этот код
   $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. Заключение

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

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

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

Комментарии (9)


  1. kolbaskinmax
    18.11.2021 19:23
    +2

    Если у нас 150 запросов к БД в разделе с каталогом, может с каталогом не все в порядке?


    1. tempick
      18.11.2021 19:44

      меня однажды попросили переписать сайт с битрикса на «что-то другое» потому что сайт постоянно падал, ломался. Студии просили за починку немалые деньги, но через небольшое время снова что-то отваливалось. Ну владельцы посоветовались и решили переписать сайт на чем угодно, только слезть с иглы битрикса.
      Я с битриксом работал очень мало и решил поглядеть в процессе переноса как там устроено всё.
      Ну, глянул что по обращениям к бд — на главной странице, где выводятся

      • Список объявлений
      • Последняя новость
      • Около десятка баннеров

      было тоже 100 с лишним запросов к бд))

      UPD: Вообще, стало интересно проанализировать какие sql-запросы использует битрикс. Пошёл устанавливать демо-версию. Если будут интересные наблюдения — напишу статью. Вроде такого ещё нет на хабре


      1. Areso
        18.11.2021 21:08

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

        Это одна из причин, по которой в русскоязычном интернете под битрикс предусмотрены отдельные тарифные планы, с учётом, так сказать, особенностей данного ПО.


    1. ArtemPervushin Автор
      18.11.2021 21:13

      Это же для примера цифра. Тут лишь количество одновременных запросов от пользователей важно.


  1. dopusteam
    18.11.2021 22:08
    +1

    if($obCache->InitCache(36000, serialize($arFilter), "/iblock/catalog"))

    $dbRes = CIBlockSection::GetList(array(), $arFilter, false, array("ID"));

    У Вас ключ для кэша по фильтру только формируется и не включает запрашиваемые столбцы?


    1. ArtemPervushin Автор
      19.11.2021 10:24

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


  1. ErnestMiller
    19.11.2021 00:49

    Лепите посты из документации битрикса? У него документация, конечно, отвратительная, но не на столько чтобы это удостаивалось отдельного поста.


    1. ArtemPervushin Автор
      19.11.2021 09:53

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


  1. FAT
    19.11.2021 09:27

    Стараюсь никогда не вешать создание кеша на пользователей, а выполняю обход каталога по крону (если кеш был очищен), для этого использую флаги, чтобы крон не гонял в холостую