Кеширование в Битрикс

Share

Принцип работы и виды кеша в Битрикс

Виды кеша:

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


Новое универстальное АПИ кеширования в Битрикс на D7

В новом API D7 в Битрикс появился замечательный класс Bitrix\Main\Data\Cache. Он позволяет кешировать HTML вывод и переменные, пример работы с классом:

<?php
// пространство имен для работы с кешем
use \Bitrix\Main\Data\Cache;
// cлужба кеширования
$cache = Cache::createInstance();
// папка, в которую положем кеш
$cachePath = 'mycachepath';
// срок годности кеша (в секундах)
$cacheTtl = 3600;
// имя кеша (тег)
$cacheKey = 'mycachekey';
// если кеш есть
if ($cache->initCache($cacheTtl, $cacheKey, $cachePath)) {
// получаем кеш в переменную
$vars = $cache->getVars();
// выводим HTML пользователю в браузер
$cache->output();
}


Методы класса Bitrix\Main\Data\Cache

Статические методы:

  1. \Bitrix\Main\Data\Cache::createInstance() создает объект для последующей работы не статических методов
  2. \Bitrix\Main\Data\Cache::clearCache($initDir) очищает кеш в папке /bitrix/cache/$initDir

Не статические методы:

  1. $cache->initCache($TTL, $uniqueString, $initDir = false, $baseDir = "cache") — инициализация кеша, проверяет существование кеша, вычитывает данные:
  2. $TTL время жизни в секундах
  3. $uniqueString уникальное имя
  4. $initDir папка, где будет кеш (внутри $baseDir). Если не указать, то будет браться из текущей запрошенной страницы, для каждой отдельной страницы будет создаваться новый кеш, хотя данные там одни и те же, объем кеша будет огромный, а пользы будет мало, рекомендуется всегда указывать папку
  5. $baseDir папка, внутри /bitrix, менять не рекомендуется, потому что кеш должен храниться в /bitrix/cache
  6. $cache->startDataCache($TTL = false, $uniqueString = false, $initDir = false, $vars = array(), $baseDir = "cache") начинает процесс кеширования. Дальше данные, которые выводятся в браузер, будут записываться (используется буфер вывода PHP). Все параметры как у initCache, только есть еще $vars:
  7. $TTL время жизни в секундах
  8. $uniqueString уникальное имя
  9. $initDir папка, где будет кеш (внутри $baseDir). Если не указать, то будет браться из текущей запрошенной страницы, для каждой отдельной страницы будет создаваться новый кеш, хотя данные там одни и те же, объем кеша будет огромный, а пользы будет мало, рекомендуется всегда указывать папку
  10. $vars переменные, которые сохранятся в кеш. Далее в коде переменные можно еще передать в endDataCache(). Параметр избыточный, передавать сюда данные не рекомендуется. Если вы вызывали initCache(), то параметры в startDataCache() передавать уже не стоит, вызывайте без параметров
  11. $initDir папка, где будет кеш (внутри $baseDir). Если не указать, то будет браться из текущей запрошенной страницы, для каждой отдельной страницы будет создаваться новый кеш, хотя данные там одни и те же, объем кеша будет огромный, а пользы будет мало, рекомендуется всегда указывать папку
  12. $cache->abortDataCache() останавливает кеширование
  13. $cache->endDataCache($vars = false) сохраняет кеш. $vars переменные, которые стоит сохранить. Если переменные передаются сюда, то переданные в startDataCache() игнорируются
  14. $cache->output() выводит в браузер HTML из кеша
  15. $cache->getVars() получает переменные из кеша
  16. $cache->clean($uniqueString, $initDir = false, $baseDir = "cache") удаляет кеш с именем $uniqueString в папке $initDir
  17. $cache->cleanDir($initDir = false, $baseDir = "cache") удаляет весь кеш в папке $initDir

Мы можем не использовать вызов $cache->output(), если работаем только с переменными. Если работаем только с HTML — так же можем не вызывать $cache->getVars().

HTML не требуется передавать в какую-то функцию, чтобы он попал в кеш, просто отдавайте в браузер. Переменные можно сохранять не только скалярные, а все, которые можно сериализовать (массивы, объекты…).

Хранение кеша по умолчанию в /bitrix/cache.


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


Тегированный кеш в Битрикс D7 (он же Сache Dependencies)

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

Рассмотрим пример с инфоблоком. Есть инфоблок Новости ID 4, данные из него выводятся на главной странице, на странице списка новостей, так же для каждой новости есть детальная страница. Это всё отдельные файлы кеша. Когда мы добавляем какую-то новость, мы не знаем кеш каких страниц надо сбросить. API инфоблока говорит сбросить кеш по тегу iblock_id_4, а к тегу уже привязаны десятки файлов, которые удаляются.

Своего кеша у taggedCache нет, теги хранятся в базе данные в таблице b_cache_tag.

Пример работы кеширования с тегами:

<?php
// пространство имен для работы с кешем
use \Bitrix\Main\Data\Cache;
use \Bitrix\Main\Application;
// cлужба кеширования
$cache = Cache::createInstance();
// служба пометки кеша тегами
$taggedCache = Application::getInstance()->getTaggedCache();
// чтобы тегированный кеш нашел что ему сбрасывать, необходим одинаковый путь в $cache->initCache() и $taggedCache->startTagCache(), у нас путь указан в $cachePath
$cachePath = 'mycachepath';
$cacheTtl = 3600;
$cacheKey = 'mycachekey';
// если кеш есть
if ($cache->initCache($cacheTtl, $cacheKey, $cachePath)) {
// получаем кеш в переменную
$vars = $cache->getVars();
// тут можно вывести данные в браузер, через $cache->output(); и тогда получится замена классу CPageCache или вернуть return $vars
}
// если кеша нет
elseif ($cache->startDataCache()) {
// начинаем записывать тегированый кеш
$taggedCache->startTagCache($cachePath);
$vars = [
'date' => date('r'),
'rand' => rand(0, 9999), // Если данные закешированы - число не будет меняться
];
// кеш сбрасываем при изменении данных в инфоблоке с ID который передаем
$taggedCache->registerTag('iblock_id_1');
// если понимаем что, что-то пошло не так, кеш можно не записывать
$cacheInvalid = false;
if ($cacheInvalid) {
$taggedCache->abortTagCache();
$cache->abortDataCache();
}
// заканчиваем записывать тегированый кеш
$taggedCache->endTagCache();
// записываем результат в тегированный кеш
$cache->endDataCache($vars);
}
// данные будут обновляться раз в час или при обновлении данных в инфоблоке с ID 1
print_r($vars);

Очистка кеша по тегу:

<?php
// пространство имен для работы с кешем
use \Bitrix\Main\Application;
// служба пометки кеша тегами
$taggedCache = Application::getInstance()->getTaggedCache();
// там где нужно, например на отдельной странице чистим кеш по тегу. В данному случае очистится кеш, который зависит от инфоблока с ID 1
$taggedCache->clearByTag('iblock_id_2');


Получение экземпляра класса taggedCache

$taggedCache = \Bitrix\Main\Application::getInstance()->getTaggedCache();

Методы класса тегированного кеша

  1. $taggedCache->startTagCache($relativePath) путь, который будет очищаться при удалении кеша по тегу. Путь передавать тот же, что и в $cache->initCache()
  2. $taggedCache->endTagCache() окончание, сохраняет привязку путей к тегам в базу данных
  3. $taggedCache->abortTagCache() останавливает кеширование. Вызывать когда запущено кеширование, но оно уже не требуется
  4. $taggedCache->registerTag($tag) привязывает тег к пути кеша, указанному ранее при вызове startTagCache()
  5. $taggedCache->clearByTag($tag) очистка кеша по тегу


Управляемый кеш (managed cache)

Почему этот кеш называется управляемый — не ясно, управлять им особо не выходит. Managed cache в Битрикс это такая прослойка над обычным классом кеширования для более быстрой работы и компактного кода. Используется чаще всего для кеширования выборок отдельных таблиц.

Сразу начну с минусов:

  1. К этому кешу не привязать теги, без горы костылей
  2. В старых версиях (где-то до 19 версии) при вызове cleanAll() управляемого кеша, удаляется так же весь кеш, на который установлены теги

Простой пример работы с классом:

<?php
// пространство имен для работы с кешем
$managedCache = Bitrix\Main\Application::getInstance()->getManagedCache();
// ключ, по которому сохраняем и получаем данные
$uniqId = 'my_cache_key';
// время жизни кеша
$ttl = 30;
// считываем кеш с диска
$managedCache->read($ttl, $uniqId);
// получаем данные из считанного файла
$res = $managedCache->get($uniqId);
// если данных нет
if ($res === false) {
// генерируем данные, например у нас тут тяжелая логика
$res = date('r');
// сохраняем данные (пока будут храниться в памяти)
$managedCache->set($uniqId, $res);
}
// работаем с данными
var_dump($res);

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

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

Крупные недочеты:

  1. Пока на диске есть кеш по вашему ключу, новые данные сохранить не получится. Надо сперва удалить старые, а потом вызвать read(), хотя мы точно знаем что данных нет. Read() надо вызывать, потому что там устанавливается ttl, а он обязателен для сохранения
  2. В функции getImmediate() требуется указывать ttl, хотя он не используется. TTL нужен только при сохранении кеша. При том TTL не хватает при вызове setImmediate(), там то он нужен. Но так как setImmediate() не принимает в параметрах TTL, перед его вызовом требуется вызов read() для указания TTL

Получение экземпляра класса managedCache

$managedCache = Bitrix\Main\Application::getInstance()->getManagedCache();

Методы класса Bitrix\Main\Data\ManagedCache

  1. $managedCache->read($ttl, $uniqueId, $tableId = false) читает файл кеша, на случай если мы какие-то данные добавим. $ttl время жизни, $uniqueId — уникальное имя, $tableId — папка в которой сохранится файл (относительно /bitrix/managed_cache). Папку указывать не обязательно
  2. $managedCache->getImmediate($ttl, $uniqueId, $tableId = false) получение данных из кеша без предварительного считывания. $ttl — ни на что не влияет, не понятно для чего добавили его, остальное как в пункте 1
  3. $managedCache->get($uniqueId) получить данные, которые должны быть предварительно считаны с помощью read функции из пункта 1
  4. $managedCache->set($uniqueId, $val) добавление данных по имени $uniqueId. Чтобы данные добавились и сохранились, предварительно надо вызвать read из пункта 1. Значение может быть как скалярным значением, так и другим, которое можно сериализовать. Данные сохраняются на диск при подключении эпилога
  5. $managedCache->setImmediate($uniqueId, $val) установка значения с последующим моментальным сохранением данных на диск, предварительно должна быть вызвано read(). Буфер при этом очищается и если вы снова захотите работать с $uniqueId, то надо будет вызвать заново read()
  6. $managedCache->clean($uniqueId, $tableId = false) удаление кеша по имени и папке
  7. $managedCache->cleanDir($tableId) удаление всех кешей в папке
  8. $managedCache->cleanAll() удаление всего управляемого кеша. Где-то до 19 версии битрикс удаляется почему-то еще и весь тегированный кеш
  9. Bitrix\Main\Data\ManagedCache::finalize() сохранение данных на диск. Автоматически вызывается в эпилоге битрикса


Неуправляемый кеш

Кеширование называется неуправляемым, потому что кеш не перестраивается автоматически после модификации исходных данных и действует в течение указанного времени после создания.

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

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

  1. Система сохраняет результат выполнения кода в файл
  2. При следующем запросе вместо выполнения кода отдает сохраненный файл
  3. Файл хранится указанное время, после чего удаляется

Пример использования неуправляемого кеширования:

use Bitrix\Main\Application;

$cache = Application::getInstance()->getCache();

// проверяем наличие кеша
if ($cache->initCache(3600, 'cache_key'))
{
// получаем данные из кеша
$data = $cache->getVars();
}
elseif ($cache->startDataCache())
{
// если кеша нет, получаем данные из базы
$data = getDataFromDatabase();

// сохраняем результаты в кеш
$cache->endDataCache($data);
}