{ "index": 184, "slug": "editorial-2022-11-field-bitrix-performance", "title": "Когда тормозит Bitrix-страница: как найти границу проблемы и не сломать кеш", "excerpt": "Практический разбор медленной Bitrix-страницы: отделяем запрос, компонент, кеш и шаблон, проверяем ключи результата и принимаем только обратимые решения.", "contentHtml": "

Пользователь открывает каталог, ждёт дольше обычного и обновляет страницу. В чате появляется короткий диагноз: «тормозит Bitrix». После него разработчик уменьшает JavaScript, администратор очищает весь кеш, а владелец сервиса просит увеличить сервер. Страница может не измениться, зато команда теряет исходное состояние. Нельзя понять, что проверяли, какой слой дал задержку и что безопасно вернуть. Цена ошибки — лишняя нагрузка, повторная работа и риск показать одному посетителю результат другого.

\n

Тезис простой: производительность Bitrix-страницы нужно разбирать по границам, а не по названию платформы. Сначала фиксируем один маршрут и его входы. Затем разделяем компонент, его кеш и шаблон. Только после этого выбираем небольшой diff и критерий проверки. Если вход кеша неизвестен, правильное действие — остановиться и уточнить контракт, а не отключать кеш наугад.

\n

Механизм: что именно формирует ответ

\n

У страницы есть несколько последовательных слоёв. HTTP-запрос выбирает маршрут и параметры. Компонент получает эти параметры и строит данные. Встроенное кеширование решает, можно ли вернуть сохранённый результат или нужно выполнить код заново. Шаблон превращает результат компонента в HTML. Браузер получает уже собранный ответ и отдельно тратит время на его разбор, стили и скрипты.

\n

Эти слои связаны, но не доказывают друг друга. Имя шаблона не показывает, какой SQL выполнился. Большой HTML не доказывает, что база медленная. Настройка кеширования не доказывает, что конкретный запрос получил cache hit. В Bitrix метод StartResultCache возвращает false, когда действующий результат можно вывести, и true, когда компонент должен сформировать результат. Это контракт ветвления, а не замер времени страницы.

\n

Ключ кеша должен учитывать каждый вход, который меняет HTML. Если результат зависит от сайта, компонента, шаблона, параметров и сегмента посетителя, эти различия нельзя скрыть в коде шаблона. Иначе две разные страницы могут использовать один сохранённый результат. Если часть результата нужна после чтения кеша, компонент может передать выбранные ключи через SetResultCacheKeys. Это управляет составом данных, доступных после кеширования; оно не ускоряет произвольный SQL и не исправляет неверный ключ.

\n

Учебный пример с отрицательной веткой

\n

Ниже — ограниченный пример. Он не запускает Bitrix, не обращается к базе и не измеряет ответ. Модель только проверяет, что перед изменением шаблона назван полный набор входов кеша. В реальном проекте список нужно подтвердить по компоненту, параметрам и условиям, которые действительно меняют HTML.

\n
<?php\n$requiredKeyParts = [\n    'SITE_ID',\n    'component',\n    'template',\n    'arParams',\n    'visitor-segment',\n];\n\n$declaredKeyParts = [\n    'SITE_ID',\n    'component',\n    'template',\n    'arParams',\n];\n\n$missing = array_values(array_diff($requiredKeyParts, $declaredKeyParts));\n\nif ($missing !== []) {\n    throw new RuntimeException(\n        'change-blocked: missing cache input ' . implode(', ', $missing)\n    );\n}\n\n$rollbackTemplate = 'catalog-grid';\n$nextTemplate = 'catalog-grid-minimal';
\n

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

\n

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

\n
\"Маршрут
Схема показывает порядок проверки границ. Она не является профилем живой страницы и не содержит production-таймингов.
\n

Симптом → причина → проверка → действие

\n
Диагностическая карта перед изменением Bitrix-страницы
СимптомВероятная причинаПроверкаДействие
Каталог медленный на одном URLСмешаны маршрут и общий разговор о платформеЗафиксировать URL, параметры, роль и вариант страницыПовторить один и тот же вход
Очистка кеша временно меняет поведениеИзменили состояние, но не нашли зависимостьСверить ветку кеша и полный список входовНе очищать весь кеш как доказательство
В ключе нет внешнего признакаHTML зависит от данных, которых нет в контрактеПроверить, меняет ли признак результат компонентаОстановить diff и назвать недостающий вход
Виноватым объявили шаблонВидимый файл приняли за источник задержкиОтделить сбор данных от рендера HTMLСобрать артефакт именно на нужной границе
После оптимизации цифра измениласьСравнили разные условия или разные кеш-состоянияПовторить исходный сценарий и способ измеренияОставить только подтверждённый diff
Нет доступа к профилю или логуГипотезу пытаются выдать за фактЗаписать ограничение и владельца следующего шагаНе утверждать причину без артефакта
\n

Как читать компонентный кеш

\n

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

\n

Затем отделите две задачи. Первая — решить, можно ли повторно использовать результат. Вторая — определить, какие данные должны быть доступны при выводе этого результата. SetResultCacheKeys относится ко второй задаче. Нельзя применять его как универсальную настройку производительности. Если компонент не кешируется или ключ строится неполно, список полей не устранит повторные вычисления.

\n

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

\n

Порядок диагностики

\n
  1. Запишите наблюдаемый симптом: маршрут, вариант страницы, условия доступа и шаг, на котором пользователь ждёт. Не добавляйте миллисекунды, SQL или cache hit-rate, если их не измеряли.
  2. Назначьте четыре границы: request, component, cache и template. Для каждой укажите владельца и один доступный артефакт: код, конфигурацию, лог или разрешённый профиль.
  3. Составьте cache contract. Перечислите параметры и внешние признаки, которые могут менять HTML. Неизвестный вход пометьте как неизвестный, а не удаляйте из записи.
  4. Проверьте отрицательный путь. Если нет владельца компонента, недоступен лог, различаются входы или неизвестен внешний признак, остановите изменение и сформулируйте недостающий факт.
  5. Выберите одну гипотезу и один артефакт, который отличит её от соседней. Не запускайте сразу очистку кеша, переписывание шаблона и изменение SQL.
  6. Сделайте один обратимый diff. Сохраните старый шаблон, старый режим и точку возврата. Не объединяйте в один шаг изменение ключа, TTL, параметров и структуры HTML.
  7. Повторите исходный сценарий тем же способом. Отдельно сравните правильность HTML, доступность данных и измеряемый сигнал. Один изменившийся показатель не доказывает улучшение всей цепочки.
  8. Зафиксируйте результат. Если гипотеза не подтверждена, верните diff и оставьте запись «не подтверждено». Если подтверждена, сохраните evidence и критерий, по которому изменение можно будет проверить снова.
\n

Ограничения и случаи остановки

\n

Эта схема не заменяет профилирование. Без реального запроса нельзя назвать тяжёлый SQL. Без лога нельзя утверждать длительность PHP. Без повторяемого браузерного сценария нельзя объяснить задержку загрузки скриптов. Документация Bitrix описывает API и режимы платформы, но не знает самописный компонент, его интеграции и данные конкретного сайта.

\n

Остановитесь, если один и тот же URL получает разный HTML по неописанному условию, если компонент меняет состояние вне своего контракта, если эксперимент запрещён на рабочем трафике или если результат нельзя безопасно откатить. В таком случае полезный итог — не «причина найдена», а точное ограничение: какой факт отсутствует, где его получить и кто отвечает за следующий шаг.

\n

Учебный код выше нельзя переносить в production как готовую оптимизацию. В нём нет проверки версии ядра, политики персональных данных, реального состава параметров, схемы инвалидирования и нагрузки. Его роль — показать stop condition. Рабочее решение требует локальной проверки и отдельного плана возврата.

\n

Проверяемый критерий готовности

\n

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

\n

Если на любой вопрос отвечает «обычно Bitrix делает так», работа не готова. Замените общую фразу конкретным неизвестным: «не установлено, влияет ли группа пользователя на HTML», «не подтверждён владелец шаблона» или «нет разрешённого профиля для этого маршрута». Такая формулировка не обещает ускорение. Она делает следующий шаг проверяемым.

\n

Проверяемые источники

\n" }