1С-Битрикс Data Cache

Разбираем принцип работы кэша в 1С-Битрикс на ядре D7, пример реализации кэширования данных с комментариями в коде. Нюансы использования.

Все мы знаем что скорость генерации динамической страницы (в случае когда данные берутся из базы) очень сильно зависит от скорости работы самой базы и сложности запросов к ней. Иногда, из-за огромного количества запросов, время создания страницы доходит до нескольких секунд. А если учесть тот факт что мы достаем данные с помощью API 1С-Битрикс, в котором с построением запросов и структурой таблиц вообще все плохо, когда например активность элемента инфоблока (записи в таблице) реализована на типе VARCHAR со значением "Y", хотя можно было сделать например TINYINT(1) и использовать 0/1, то возникает вопрос, как это ускорить. И тут нам приходит на помощь кэширование данных.

В данной статье опишу принцип работы и использования Data Cache при помощи стандартных методов 1С-Битрикс. Этот тип позволяет кэшировать только данные. В битриксе существуют и другие типы, которые кэшируют например кусок страницы (HTML-код который вывелся на экран), но об этом в другой статье.

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

У нас есть код нашего метода. Не будем углубляться в тонкости каким способом он реализован, опустим ООП, неймспейсы и прочие прелести программирования. Для наглядного примера лучше подойдет статический. Кратко, понятно и ничего лишнего.

<? class MyClass { public static function getData($a, $b, $c) { /* тут у нас кусок кода по получению данных в $result ... */ return $result; } } ?>

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

<? class MyClass { public static function getData($a, $b, $c) { //Создаем объект для работы с кэшем $obCache = \Bitrix\Main\Data\Cache::createInstance(); //Задаем время кеширования (при желании можно вынести на вход метода) $cacheTime = 3600; //Задаем ID кэша, для этого помещаем значения всех входных переменных в массив, а затем серилизуем его, что бы получить ключ в виде строки. $cacheId = serialize([$a, $b, $c]); //Для начала проверяем, существуют ли данные в кэше if($obCache->initCache( $cacheTime, //Время кэширования в секундах, это промежуток времени, в течении которого будет отдаваться один и тот же результат при одинаковых входных данных, даже если данные в базе поменялись $cacheId, //ID кэша __CLASS__ . '/' . __FUNCTION__ //Путь до папки с файлом кэша. Очень удобно использовать название класса и метода. При такой конструкции путь получится таким /bitrix/cache/MyClass/getData )) { //Если данные в кэше есть, то возвращаем их. return $obCache->GetVars(); } //Если код добрался до этой строчки, значит данных в кэше он не обнаружил, поэтому получаем их и кэшируем. //Стартуем кэш if($obCache->startDataCache()) { /* тут у нас кусок кода по получению данных в $result это тот же кусок кода из метода выше (тот что без кэша) ... */ //После получения данных, обязательно проверяем их, например получили ли мы запись из таблицы. Если мы не получили ничего, то и нет смысла кэшировать это ничего. //Предположим что при удачном получении у нас в $result будут какие-то данные, а при неудачном будет лежать NULL или FALSE //Данные получены if($result) { //Сохраняем данные в кэш $obCache->endDataCache($result); } else { //Не сохраняем (сбрасываем кэш) $obCache->AbortDataCache(); } } return $result; } } ?>

Почему я проверяю данные перед кэшированием? Все очень просто, объясняю как работает кэш в 1С-Битрикс.

При сохранении данных в кэш, 1С-Битрикс создает отдельный файл для каждого ID кэша. В нашем случае это уникальная комбинация из значений переменных $a, $b, $c. В файл кэша помещается серилизованный массив с данными (в виде строки) и служебная информация о дате создания файла кэша и дате когда он утрачивает свою актуальность.

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

Но это еще не все, если вы считаете что после истечения времени жизни кэша (переменная $cacheTime в нашем методе) файл с закэшированными данными удалится, то вы глубоко заблуждаетесь. Эти файлы будут продолжать лежать на сервере и копиться, до тех пор пока вы не удалите их руками или не запустите очистку кэша в админке 1С-Битрикс.

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

  • Как часто меняются данные, в связи с этим подобрать оптимальное время кэширования.
  • Сохранять в кэш только положительный результат, а не любой, во избежание переполнения места на диске.
  • Использовать кэширование только в тех случаях, когда на входе нет бесконечно большого количества вариантов значений, например не рекомендую использовать кэш при фильтрации товаров каталога, потому что там очень много вариантов фильтра. Если например фильтр состоит только из галок, то количество вариантов фильтра будет 2 в степени количества галок в фильтре. А представьте если там еще ползунок, да еще двухсторонний и не один?
  • Не кидать в кэш все что вернул битрикс, а только то что нужно вам (его API возвращает кучу лишнего, при чем бесполезная информация частенько превышает все пределы разумного).

И на последок хочу предложить альтернативный вариант, который с моей точки зрения более правильный (предыдущий же был от разработчиков 1С-Битрикс).

Опущу комментарии которые присутствовали в первом варианте, добавлю поясняющие почему именно так.

<? class MyClass { public static function getData($a, $b, $c) { $obCache = \Bitrix\Main\Data\Cache::createInstance(); $cacheTime = 3600; $cacheId = serialize([$a, $b, $c]); if($obCache->initCache( $cacheTime, $cacheId, __CLASS__ . '/' . __FUNCTION__ )) { return $obCache->GetVars(); } //Если в кэше данных нет то получаем их еще до старта кэша, потому что например if($obCache->startDataCache()) по какой то причине может не сработать и метод нам ничего не вернет /* тут у нас кусок кода по получению данных в $result ... */ //Делаем проверку, что мы получили какой-то полезный результат, а не пустоту if($result) { //И только тогда стартуем кэш и сохраняем if($obCache->startDataCache()) { $obCache->endDataCache($result); } } return $result; } } ?>

Теги: 1С-Битрикс, Cache, Данные, Ядро D7