Ускорение работы сайта через механизмы кэширования в Битриксе

Раздел: Администрирование и оптимизация -> Оптимизация производительности

Кэширование в Bitrix: варианты реализации и оптимизация

Как добиться максимальной производительности с тегированным кэшем?

Рекомендуемое решение: Bitrix\Main\Data\Cache с тегами и временем жизни.

use Bitrix\Main\Data\Cache;

$cache = Cache::createInstance();
$cacheTime = 3600; // 1 час
$cacheId = 'my_custom_data';
$cachePath = '/my_module/';

if ($cache->initCache($cacheTime, $cacheId, $cachePath)) {
    $result = $cache->getVars();
} else {
    // Генерация данных
    $data = [];
    \Bitrix\Main\Loader::includeModule('iblock');
    $elements = \Bitrix\Iblock\ElementTable::getList([
        'filter' => ['IBLOCK_ID' => 1, 'ACTIVE' => 'Y'],
        'select' => ['ID', 'NAME'],
        'limit' => 100
    ])->fetchAll();
    foreach ($elements as $el) {
        $data[$el['ID']] = $el['NAME'];
    }
    $cache->startDataCache();
    $cache->endDataCache($data);
    $result = $data;
}

// Использование $result

Php http cache (http-кэширование в php)

Типичные ошибки:

  • Не очищается кэш после изменения данных. Решение: использовать теги для автоматической очистки через $cache->registerTag('iblock_id_1').
  • Ключ кэша не уникален – данные разных пользователей смешиваются. Решение: добавлять в $cacheId контекст (язык, сайт, группа пользователя).
  • Переполнение файлового кэша. Решение: ограничить время жизни или использовать внешние хранилища (memcached/redis).

Цель: кэширование результатов сложных SQL-запросов, вычислений, данных, которые редко изменяются.

Как закэшировать результат простого запроса с помощью CPHPCache?

$obCache = new CPHPCache();
$cacheTime = 86400; // 24 часа
$cacheId = 'simple_data_' . SITE_ID;
$cachePath = '/simple/';

if ($obCache->InitCache($cacheTime, $cacheId, $cachePath)) {
    $result = $obCache->GetVars();
} else {
    // Формирование данных
    $result = ['time' => time(), 'text' => 'some heavy operation'];
    if ($obCache->StartDataCache()) {
        $obCache->EndDataCache($result);
    }
}

Wp content object cache php (кэш объектов в wp-content (wordpress))

Проблема: отсутствие автоматической очистки при изменении данных. Приходится вручную вызывать CPHPCache::ClearCache($cacheId, $cachePath).

Как кэшировать HTML-вывод компонента для неавторизованных пользователей?

Используется технология композитного кэширования (Bitrix Composite Cache). Настройка в файле .settings.php:

'cache' => [
    'type' => [
        'class' => '\\Bitrix\\Main\\Data\\CacheEngineFiles',
        'use_cluster' => false
    ],
    'html' => [
        'ttl' => 3600
    ]
]

Bitrix php cache (кэширование в bitrix (php))

Включить опцию "Кэшировать для гостей" в настройках компонента. Результат – статический HTML отдается без выполнения PHP.

Ошибки: компоненты с динамическими данными (корзина, личный кабинет) требуют исключения из кэша через параметр COMPOSITE_FRAME_MODE.

Как использовать memcached для внешнего кэша?

// .settings.php
'cache' => [
    'type' => [
        'class' => '\\Bitrix\\Main\\Data\\CacheEngineMemcache',
        'servers' => [
            [
                'host' => '127.0.0.1',
                'port' => '11211'
            ]
        ]
    ]
]

После настройки все кэширование автоматически переключается на memcached. Ускоряет доступ и снимает нагрузку с файловой системы.

Требуется установленное расширение PHP memcached. Необходимо следить за объемом памяти в memcached – при переполнении ключи удаляются.

Расширенные примеры кэширования с детальными пояснениями

Пример 1. Кэширование с тегами и автоматической очисткой при обновлении инфоблока

Пример
use Bitrix\Main\Data\Cache;
use Bitrix\Iblock\ElementTable;

$cache = Cache::createInstance();
$ttl = 7200;
$cacheId = 'iblock_elements_' . SITE_ID . '_' . LANGUAGE_ID;
$cachePath = '/iblock_data/';

if ($cache->initCache($ttl, $cacheId, $cachePath)) {
    $elements = $cache->getVars();
} else {
    $elements = [];
    $rs = ElementTable::getList([
        'filter' => ['IBLOCK_ID' => 2, 'ACTIVE' => 'Y'],
        'select' => ['ID', 'NAME', 'CODE', 'TIMESTAMP_X'],
        'order' => ['SORT' => 'ASC']
    ]);
    while ($el = $rs->fetch()) {
        $elements[$el['ID']] = [
            'name' => $el['NAME'],
            'code' => $el['CODE'],
            'date' => $el['TIMESTAMP_X']->toString()
        ];
    }
    
    $cache->startDataCache();
    $cache->registerTag('iblock_id_' . 2); // тег по инфоблоку
    // Можно добавить теги для каждого элемента
    foreach (array_keys($elements) as $id) {
        $cache->registerTag('iblock_element_' . $id);
    }
    $cache->endDataCache($elements);
}

// Вывод
foreach ($elements as $id => $data) {
    echo "{$data['name']} ({$data['code']}) - {$data['date']}\n";
}
Результат:
Товар1 (tovar1) - 2025-03-28 14:22:10
Товар2 (tovar2) - 2025-03-28 16:05:33
...

Пояснение: при изменении элемента инфоблока метод CIBlockElement::SetPropertyValues (и другие) вызывает очистку всех кэшей с соответствующими тегами.

Пример 2. Кэширование результатов вызова внешнего API

Пример
use Bitrix\Main\Data\Cache;

function getCurrencyRates() {
    $cache = Cache::createInstance();
    $ttl = 1800; // 30 минут
    $cacheId = 'currency_rates_' . SITE_ID;
    $cachePath = '/currency/';
    
    if ($cache->initCache($ttl, $cacheId, $cachePath)) {
        return $cache->getVars();
    } else {
        $url = 'https://api.exchangerate-api.com/v4/latest/USD';
        $response = file_get_contents($url);
        if ($response === false) {
            // вернуть устаревшие данные или заглушку
            return false;
        }
        $data = json_decode($response, true);
        $rates = $data['rates'];
        $cache->startDataCache();
        $cache->endDataCache($rates);
        return $rates;
    }
}

$rates = getCurrencyRates();
print_r($rates);
Результат:
Array
(
    [AED] => 3.6732
    [AFN] => 77.5
    [ALL] => 103.85
    ...
)

Пояснение: кэширование защищает от повторных запросов к внешнему API в случае временной недоступности (возвращается кэш). Установлен короткий TTL для актуальности курсов.

Пример 3. Кэширование сложных вычислений с привязкой к пользователю

Пример
$userId = \Bitrix\Main\Engine\CurrentUser::get()->getId();
$cacheId = 'user_dashboard_' . $userId;
$cachePath = '/dashboard/';

$cache = Cache::createInstance();
if ($cache->initCache(300, $cacheId, $cachePath)) {
    $dashboard = $cache->getVars();
} else {
    // Вычисления: количество заказов, любимые категории и т.д.
    $dashboard = [
        'orders_count' => getOrdersCount($userId),
        'favorite_categories' => getFavCategories($userId),
        'last_order_date' => getLastOrderDate($userId)
    ];
    $cache->startDataCache();
    // Можно добавить теги для очистки при изменении заказов пользователя
    $cache->registerTag('user_' . $userId);
    $cache->endDataCache($dashboard);
}
return $dashboard;

Важно: при изменении данных пользователя (оформление заказа) очистить кэш по тегу user_N. Например, в обработчике события OnSaleOrderSaved вызывать \Bitrix\Main\Data\Cache::clearCacheByTag('user_' . $userId).

Кэширование в Bitrix (PHP) - comments

En
Bitrix php cache (php)