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

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

\n

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

\n

Сначала отделите границы, потом меняйте код

\n

Одна правка должна отвечать на один вопрос. Например: «входит ли группа пользователя в зависимость кеша этого компонента?» Это проверяемый вопрос. «Почему Bitrix медленный?» — нет. Пока вопрос не ограничен, нельзя выбрать ни инструмент, ни безопасное действие.

\n

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

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

Что именно гарантирует компонентный кеш

\n

Встроенное кеширование Bitrix начинается с StartResultCache. При действующем кеше метод возвращает false, выводит сохранённое содержимое и заполняет $arResult. При недействительном кеше он возвращает true; компонент получает данные, подключает шаблон, а результат сохраняется при вызове IncludeComponentTemplate или ShowComponentTemplate. Это описание ветки компонента, а не замер всей страницы.

\n

Документация называет базовые части зависимости: сайт, имя компонента, имя шаблона и входные параметры $arParams. Дополнительное условие передают через additionalCacheID. В официальном примере в него входят группы пользователя. Если HTML зависит от права, языка или другого значения, это значение должно участвовать в зависимости результата. Иначе один сохранённый HTML может попасть к другому варианту посетителя.

\n

SetResultCacheKeys решает другой вопрос. Метод перечисляет поля $arResult, которые должны быть доступны при использовании встроенного кеша. Он не измеряет SQL, не уменьшает автоматически время рендера и не превращает тяжёлый компонент в быстрый. Его смысл появляется только после проверки того, какие данные нужны шаблону и коду вокруг компонента.

\n
Схема разбора производительности Bitrix-страницы: маршрут передаёт вход компоненту, компонент проверяет кеш и формирует HTML через шаблон; на каждой границе фиксируется отдельный факт.
Один запрос проходит несколько границ. Объявленная зависимость кеша помогает проверить контракт, но не заменяет измерение времени ответа.
\n

Учебный пример с согласованным результатом

\n

Ниже показана сокращённая схема. Функция loadCatalogItems условна: в проекте её нужно заменить реальным чтением данных. Группа и язык включены в дополнительный идентификатор только потому, что предположительно меняют HTML. Если это не так, их добавление лишь дробит кеш и не даёт полезной защиты.

\n
$groupKey = implode(',', array_map('intval', $USER->GetGroups()));\n$additionalCacheId = $groupKey . '|' . (string) $arParams['LANGUAGE_ID'];\n\nif ($this->StartResultCache(false, $additionalCacheId)) {\n    $items = loadCatalogItems((int) $arParams['IBLOCK_ID']);\n\n    if ($items === null) {\n        // Некорректный или запрещённый вход не сохраняем как обычный результат.\n        $this->AbortResultCache();\n        return;\n    }\n\n    $this->arResult = [\n        'SECTION_ID' => (int) $arParams['SECTION_ID'],\n        'ITEM_COUNT' => count($items),\n        'ITEMS' => $items,\n    ];\n    $this->SetResultCacheKeys(['SECTION_ID', 'ITEM_COUNT']);\n    $this->IncludeComponentTemplate();\n}
\n

Здесь null означает ошибочный или недопустимый вход, а пустой массив может быть нормальным пустым каталогом. Это различие важно: пустое состояние, которое можно безопасно показать всем посетителям с одинаковым ключом, не нужно искусственно объявлять ошибкой. AbortResultCache применяйте только когда результат действительно нельзя сохранять.

\n

Массив ITEMS нужен шаблону в ветке построения. Поля SECTION_ID и ITEM_COUNT перечислены отдельно, потому что код после компонента или модификатор результата может обращаться именно к ним. Это не универсальный список. Если шаблон зависит от другой части результата, сначала назовите её и проверьте её место в контракте.

\n

Вызов с false в первом аргументе означает, что время кеширования берётся из $arParams['CACHE_TIME']. Ненулевой CACHE_TIME ещё не доказывает попадание в кеш. Для такого вывода нужен отдельный артефакт: профиль, лог или разрешённый замер на том же маршруте и с тем же вариантом входа.

\n

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

\n
  1. Зафиксируйте симптом. Укажите один URL, вариант запроса и наблюдаемое поведение. Не добавляйте выдуманные миллисекунды, SQL или долю попаданий в кеш.
  2. Назовите границу. Найдите подключаемый компонент, его шаблон и параметры. Отдельно запишите условия, которые могут менять HTML или доступ к данным.
  3. Сверьте контракт кеша. Проверьте базовые входы и дополнительные зависимости StartResultCache. Сопоставьте их с фактическими условиями вывода.
  4. Разделите пустой и ошибочный результат. Решите, является ли пустой каталог валидным состоянием или признаком недопустимого входа. Только во втором случае рассматривайте AbortResultCache.
  5. Выберите один артефакт. Используйте доступный в проекте лог, профиль, трассировку или замер. Он должен различать две гипотезы, например промах кеша и дорогую подготовку данных.
  6. Сделайте один узкий diff. Меняйте только один параметр, зависимость или шаблон. До изменения запишите, что вернуть, если результат не подтверждён.
  7. Повторите тот же вход. Сравните прежний и новый артефакт на том же URL, варианте пользователя и наборе данных. Если вход изменился, это новый эксперимент.
\n

Быстрые исправления, которые скрывают причину

\n

Очистка всего кеша меняет состояние системы, но не объясняет стоимость формирования. После очистки первый запрос закономерно может быть тяжёлым. Выключение кеша убирает один путь и добавляет нагрузку на базу и PHP. Это не диагностика.

\n

Увеличение CACHE_TIME может уменьшить число построений, но закрепит неверный HTML, если ключ неполон. И наоборот, добавление в ключ каждого доступного признака создаст лишние варианты и усложнит обновление. Включайте только те значения, которые действительно меняют результат.

\n

Переписывать шаблон только потому, что он виден в каталоге файлов, тоже рискованно. Шаблон отвечает за вывод, но не обязан отвечать за дорогой запрос. Не смешивайте в одной правке кеш, SQL, PHP и браузер. Иначе положительный результат нельзя связать с одним изменением. Если гипотеза не подтверждается, верните именно этот diff и повторите исходный вход.

\n

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

\n

Документация Bitrix описывает API кеширования, но не знает самописный компонент, версию PHP, структуру базы, настройки окружения и реальные условия пользователя. Учебный код не заменяет профиль. Названия IBLOCK_ID, SECTION_ID, LANGUAGE_ID и группы в примере не являются данными конкретного сайта.

\n

Нельзя объявлять страницу быстрой только по факту действующего кеша. Компонент может быть быстрым, а задержка останется в другом блоке, на уровне сети, браузера или внешнего сервиса. Статья также не утверждает, что любая Bitrix-страница станет быстрее после добавления зависимости или изменения времени кеша.

\n

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

\n

Граница источников для ноября 2022 года

\n

Материал датирован ноябрём 2022 года, поэтому для API приведены архивные снимки официальной документации. Они фиксируют состояние страниц до этой даты. Текущая документация может содержать обновления и не используется здесь как доказательство исторического состояния. Собственный учебный пример показывает контракт рассуждения, но не выдаётся за результат работы конкретного сервера.

\n

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

" }