Рассмотрим как работает стандартный управляемый кеш в Битриксе:
- В настройках ядра включен управляемый кеш.
- При запросе некой страницы сайта, компоненты на ней, которым нужно закешироваться, при кешировании создают записи в таблицу b_cache_tag, в которые прописывают свой собственный идентификатор и список тегов.
- Теги определяются типом информации и модулем, откуда запрашивается информация. При запросе элементов инфоблока создается тег вида iblock_id_<IBLOCK_ID>, при запросе результатов формы создается тег вида form_<FORM_ID> и т.д. В каждом компоненте может быть несколько тегов.
- В дальнейшем, при изменении информации определяется список тегов, по которым она может быть доступна, и кеш сбрасывается адресно по этим тегам. Например, при изменении элемента инфоблока сбрасывается кеш по тегу iblock_id_<IBLOCK_ID>.
- При полном сбросе кеша очищается вся таблица b_cache_tag.
Существует инфоблок товаров (ID = 2), инфоблок брендов (ID = 4), инфоблок материалов (ID = 11).
На странице каталога выводится список товаров с иконками брендов. Теги, которые будут записаны в таблицу - iblock_id_2, iblock_id_4
На детальной странице товара выводится информация о самом товаре, информация о бренде и список материалов, прикрепленных к товару. Теги: iblock_id_2, iblock_id_4, iblock_id_11.
При изменении любого конкретного товара сбрасывается кеш всего каталога - всех страниц, на которых был запрошен CIblockElement::GetList() или GetByID() по инфоблоку каталога (iblock_id_2).
Вот список типов таких станиц в типовом каталоге: список разделов, страница раздела, страница подраздела, все списки с активным фильтром, детальные страницы, и все остальные страницы, на которых могут выводится товары. Кеш всех этих страниц сбросится при изменении любого (одно-единственного) товара.
Более того - в нашем конкретном примере - при изменении любого бренда сбросится кеш по тегу iblock_id_4 (все списки товаров и все детальные страницы), при изменении элемента материала сбросится кеш по тегу iblock_id_11 (все детальные страницы товаров).
Представим, что в каталоге 50 разделов и более 10 тысячей товаров. Ежедневно несколько контент-менеджеров добавляют новые товары, изменяют старые. В результате кеш всего каталога будет сбрасываться десятки раз за день, что сведет смысл кеширования на "нет".
Что предлагает Битрикс
Во избежание описанной ситуации, Битрикс для больших проектов советует вовсе выключить управляемый кеш. В этом случае изменения контент-менеджеров никак не влияют на публичную часть сайта, пока не будет сброшен полностью кеш сайта (подобный сброс нужно производить регулярно). Возможно, такой сценарий многим удобен, но далеко не всем - стремление отображать пользователю самую актуальную информацию требует поиска новых решений.
Кастомное решение для информационных блоков
Опишем это решение в общих понятиях с примерами в виде каталога товаров.
1. При изменении информации в административном разделе кеш по заранее заданным тегам (iblock_id_<IBLOCK_ID>) будет сбрасываться в любом случае - на этот процесс не повлиять. Чтобы сброс подобного кеша не сбрасывал реальный кеш компонентов - необходимо запретить этим компонентам добавлять указанные теги в свои записи.
Для этого перед областью кеширования вызываются функции, запрещающие установку стандартных тегов:
CIBlock::disableTagCache(2); CIBlock::disableTagCache(4); CIBlock::disableTagCache(11); |
После области кеширования вызываются обратные функции
CIBlock::enableTagCache(2); CIBlock::enableTagCache(4); CIBlock::enableTagCache(11); |
Можно продолжить использовать стандартные компоненты - CIBlock::disableTagCache(<IBLOCK_ID>); и CIBlock::enableTagCache(<IBLOCK_ID>); разместить в файле, перед и после подключения компонента, а собственные теги добавить в result_modifier.php.
Приведем примеры возможных тегов для каталога товаров:
global $CACHE_MANAGER; $CACHE_MANAGER->RegisterTag("catalog_all"); // тег для всех страница каталога товаров $CACHE_MANAGER->RegisterTag("sections_all"); // тег для всех страниц разделов каталога $CACHE_MANAGER->RegisterTag("elements_all"); // тег для всех детальных страниц $CACHE_MANAGER->RegisterTag("section_<SECTION_ID>"); // тег для конкретного раздела $CACHE_MANAGER->RegisterTag("element_<ITEM_ID>"); // тег для конкретной детальной страницы $CACHE_MANAGER->RegisterTag("tag_<TAG>"); // страница с поиском по тегу $CACHE_MANAGER->RegisterTag("brand_<BRAND_ID>"); // страница с фильтрацией по одному бренду $CACHE_MANAGER->RegisterTag("material_<ID>"); // тег для указания отображенного материала |
Конкретная детальная страница таким образом будет закеширована по следующим тегам - catalog_all, elements_all, element_1101, brand_927, material_1302, material_1303 (один элемент, один бренд, два материала). При изменении только этих указанных элементов кеш этой страницы следует сбросить. При изменении любых других элементов, кеш этой страницы нужно оставить.
3. Стандартный метод сброса кеша (по основным тегам iblock_id_<IBLOCK_ID>) больше не сбросит кеш страниц каталога товаров.
Необходимо добавить собственные обработчики на добавление\изменение элементов и разделов каталога товаров и всех связанных элементов (бренды, материалы). Также нужно добавить обработчики на изменение цен в товарах.
// элементы AddEventHandler('iblock', 'OnAfterIBlockElementAdd', 'updateCatalogItem'); AddEventHandler('iblock', 'OnAfterIBlockElementUpdate', 'updateCatalogItem'); /** * сброс кеша при изменении элементов * * @param $arFields */ function updateCatalogItem($arFields) { global $CACHE_MANAGER; if ($arFields['IBLOCK_ID'] == IBLOCK_CATALOG_ID) { // изменение Товара $CACHE_MANAGER->ClearByTag('element_'.$arFields['ID']); } if ($arFields['IBLOCK_ID'] == IBLOCK_BRAND_ID) { // изменение Бренда $CACHE_MANAGER->ClearByTag('brand_'.$arFields['ID']); } if ($arFields['IBLOCK_ID'] == IBLOCK_MATERIAL_ID) { // изменение Материала $CACHE_MANAGER->ClearByTag('material_'.$arFields['ID']); } } // разделы AddEventHandler("iblock", "OnAfterIBlockSectionAdd", 'updateCatalogSection'); AddEventHandler("iblock", "OnAfterIBlockSectionUpdate", 'updateCatalogSection'); /** * сброс кеша при изменении раздела каталога * * @param $arFields */ function updateCatalogSection($arFields) { global $CACHE_MANAGER; if ($arFields['IBLOCK_ID'] == IBLOCK_CATALOG_ID) { // изменение Раздела каталога товаров CACHE_MANAGER->ClearByTag('section_'.$arFields['ID']); } } // цены AddEventHandler('catalog', 'OnPriceAdd', 'changePriceUpdateCache'); AddEventHandler('catalog', 'OnPriceUpdate', 'changePriceUpdateCache'); /** * добавление\изменение цены вызывает сброс кеша * * @param int $ID * @param array $arFields */ function changePriceUpdateCache($ID = 0, $arFields = array()) { global $CACHE_MANAGER; $CACHE_MANAGER->ClearByTag('element_'.$arFields['PRODUCT_ID']); } |
4. Отдельной страницей можно сделать пункт управления и сброса тега по указанным типам тегов.
На ней по запросу во всплывающих страницах отображать список закешированных разделов, товаров, брендов, материалов - и по отдельному запросу сбрасывать кеш указанному конкретному элементу или разделу.
Например, вот всплывающее окно со списком закешированных брендов. У каждого бренда есть ссылка для сброса кеша. Наверху добавлена ссылка для переключения отображения “всех брендов” и “только закешированных брендов”.
Владимир Смирнов Технический директор интернет-магазина
|