1C BitrixBashRedis

Архитектура прогрева кеша для каталога на 200 тыс. SKU

Страница без кеша собиралась 2.5 секунды, а полный прогрев каталога на 200 тыс. товаров занял бы десятки часов. Как отобрал 318 нужных URL из 7329, прогрел их с троттлингом по cron и получил ответ 190 мс. Скрипты внутри.

РезультатОтвет сервера 190 мс
Александр Бутаков
Александр Бутаков
обновлено 3 мин чтения

Прогревать кеш большого каталога на Битриксе целиком — плохая идея: обход сотен тысяч страниц займёт десятки часов и сам положит сервер. Работает другое: после тяжёлого обновления базы сбросить только нужный кеш, отобрать из sitemap страницы, которые реально важны (разделы каталога и SEO-страницы), и прогреть их медленно, с паузами, по расписанию после импорта. В этом кейсе так из 7329 URL осталось 318, а ответ сервера упал с 2524 до 190 мс.

Что случилось

Время генерации страницы без попадания в кеш достигало 2524 мс. Старт PHP-процесса, инициализация сессии и десятки запросов к БД для сборки фильтра — всё это на каждый промах кеша.

Пока кеш тёплый, это незаметно. Но после ночного импорта цен кеш сбрасывался, и в этот момент приходили краулеры. Каждый их запрос — те самые 2.5 секунды работы воркера. Свободные воркеры заканчивались мгновенно, CPU уходил в 100%. Полный прогрев каталога штатными средствами занял бы десятки часов и положил бы сервис не хуже ботов.

Почему холодный кеш так дорого стоит

Страница каталога на Битриксе с умным фильтром — это много работы: ядро, сессия, запросы к инфоблокам, свойства для фильтра, SEO-данные. Кеш компонентов прячет эту цену, но только пока он есть. Любое массовое обновление (импорт из 1С, пересчёт цен, правки свойств) инвалидирует теги, и следующий посетитель платит полную цену.

Проблема не в том, что кеш сбрасывается, — так и должно быть. Проблема в том, кто первым приходит за холодной страницей. Если это ваш собственный скрипт в 11:30 утра — хорошо. Если сотня краулеров одновременно — плохо.

Шаг 1. Сбросить именно то, что устарело

Первым делом — PHP-скрипт, который чистит таблицы SEO-модуля и сбрасывает его тегированный кеш. Не весь кеш сайта, а то, что относится к SEO-данным:

PHP
<?php
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS", true);
$_SERVER["DOCUMENT_ROOT"] = __DIR__;
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

// TODO: замените на свой модуль и его тег кеша
if (\Bitrix\Main\Loader::includeModule('seo.module')) {
    \Seo\Module\Models\CacheTable::clearCache();
    $GLOBALS['CACHE_MANAGER']->ClearByTag('seo_module');
    echo "Cache cleared.\n";
}

Сброс по тегу (ClearByTag) — штатный механизм Битрикса: он инвалидирует только записи, помеченные этим тегом, и не трогает остальной кеш.

Шаг 2. Отобрать, что греть

Полный sitemap каталога — 7329 URL. Греть все — те самые десятки часов. Но посетители и поисковики приходят в основном на разделы каталога и SEO-страницы фильтра, а не на каждую карточку.

Bash-скрипт собирает именно их: SEO-страницы из отдельного sitemap и разделы каталога — из sitemap инфоблоков, отрезая от URL товара последний сегмент и убирая дубли. На выходе — 318 целевых адресов.

Шаг 3. Греть медленно

Прогрев не должен сам стать нагрузкой. wget --spider запрашивает страницы, не сохраняя их, а --wait=1 --random-wait делает паузы между запросами — сервер спокойно обслуживает реальных посетителей параллельно.

Bash
#!/bin/bash
# TODO: замените домен и путь к сайту
SITE="https://client-site.com"
DOCROOT="/var/www/client/data/www/client-site.com"

php -f $DOCROOT/clear_seo.php

SEO_URLS=$(curl -s $SITE/seo-sitemap/sitemap-1.xml | grep -oP '(?<=<loc>).*?(?=</loc>)')
IBLOCK_MAPS=$(curl -s $SITE/sitemap.xml | grep -oP '(?<=<loc>).*?(?=</loc>)' | grep 'sitemap-iblock')
SECTION_URLS=$(echo "$IBLOCK_MAPS" | xargs -I {} curl -s {} | grep -oP '(?<=<loc>).*?(?=</loc>)' | sed 's#[^/]*/*$##' | sort | uniq)

ALL_URLS=$(echo -e "$SEO_URLS\n$SECTION_URLS" | grep "http" | sort | uniq)
echo "$ALL_URLS" > /tmp/warmup_urls.txt
wget -q --spider -i /tmp/warmup_urls.txt --wait=1 --random-wait
rm -f /tmp/warmup_urls.txt

318 адресов с паузой около секунды — это минуты, а не часы.

Шаг 4. Запускать в правильный момент

Прогрев имеет смысл только после того, как данные перестали меняться. Поэтому cron стоит на окно, когда импорт цен уже закончился, а база свободна:

Bash
30 11 * * * /var/www/client/data/www/client-site.com/safe_warmup.sh

Если импорт иногда задерживается, надёжнее запускать прогрев не по часам, а последним шагом самого импорта — тогда он никогда не начнётся раньше времени.

Результат

  • Время ответа снизилось до 190 мс
  • Пики нагрузки на CPU полностью устранены
  • SEO-метатеги на 100% актуальны для краулеров
  • Рутинный ручной сброс кеша больше не нужен

Как проверить, что прогрев работает

Замерьте время до первого байта до и после прогрева на одной и той же странице:

Bash
# TODO: подставьте адрес раздела каталога
curl -s -o /dev/null -w "TTFB: %{time_starttransfer}s\n" https://client-site.com/catalog/section/

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

FAQ

Как прогреть кеш Битрикса после импорта? Сбросить только устаревший кеш по тегам, собрать из sitemap важные страницы (разделы каталога, SEO-страницы) и запросить их с паузами через wget --spider или curl. Запускать после окончания импорта.

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

Как не перегрузить сервер прогревом? Делать паузы между запросами (--wait=1 --random-wait), запускать в окно минимальной нагрузки и греть ограниченный список адресов, а не весь sitemap.

Почему страницы на Битриксе медленные после обновления цен? Импорт инвалидирует кеш компонентов, и первый посетитель получает полную сборку страницы. Прогрев сразу после импорта убирает эту задержку.

Статья была полезной?

Нужна помощь с похожей задачей?

Поддержка сайтов →