Files
progcode/editorial/agent-rewrites/184.json
T

8 lines
20 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"index": 184,
"slug": "editorial-2022-11-field-bitrix-performance",
"title": "Когда тормозит Bitrix-страница: как найти границу проблемы и не сломать кеш",
"excerpt": "Практический разбор медленной Bitrix-страницы: отделяем запрос, компонент, кеш и шаблон, проверяем ключи результата и принимаем только обратимые решения.",
"contentHtml": "<p>Пользователь открывает каталог, ждёт дольше обычного и обновляет страницу. В чате появляется короткий диагноз: «тормозит Bitrix». После него разработчик уменьшает JavaScript, администратор очищает весь кеш, а владелец сервиса просит увеличить сервер. Страница может не измениться, зато команда теряет исходное состояние. Нельзя понять, что проверяли, какой слой дал задержку и что безопасно вернуть. Цена ошибки — лишняя нагрузка, повторная работа и риск показать одному посетителю результат другого.</p>\n<p>Тезис простой: производительность Bitrix-страницы нужно разбирать по границам, а не по названию платформы. Сначала фиксируем один маршрут и его входы. Затем разделяем компонент, его кеш и шаблон. Только после этого выбираем небольшой diff и критерий проверки. Если вход кеша неизвестен, правильное действие — остановиться и уточнить контракт, а не отключать кеш наугад.</p>\n<h2>Механизм: что именно формирует ответ</h2>\n<p>У страницы есть несколько последовательных слоёв. HTTP-запрос выбирает маршрут и параметры. Компонент получает эти параметры и строит данные. Встроенное кеширование решает, можно ли вернуть сохранённый результат или нужно выполнить код заново. Шаблон превращает результат компонента в HTML. Браузер получает уже собранный ответ и отдельно тратит время на его разбор, стили и скрипты.</p>\n<p>Эти слои связаны, но не доказывают друг друга. Имя шаблона не показывает, какой SQL выполнился. Большой HTML не доказывает, что база медленная. Настройка кеширования не доказывает, что конкретный запрос получил cache hit. В Bitrix метод <code>StartResultCache</code> возвращает <code>false</code>, когда действующий результат можно вывести, и <code>true</code>, когда компонент должен сформировать результат. Это контракт ветвления, а не замер времени страницы.</p>\n<p>Документация Bitrix прямо называет базовую зависимость кеша: сайт, имя компонента, имя шаблона и входные параметры <code>arParams</code>; дополнительные условия передают вторым аргументом <code>StartResultCache</code>. Поэтому ключ кеша должен учитывать каждый вход, который меняет HTML. Если результат зависит от сегмента посетителя, эту зависимость нельзя прятать только в шаблоне: иначе разные варианты могут получить один сохранённый результат. Если часть результата нужна после чтения кеша, компонент может передать выбранные поля через <code>SetResultCacheKeys</code>. Это управляет данными, доступными после кеширования, но не ускоряет произвольный SQL и не исправляет неверный ключ.</p>\n<p>Страницы API помечают <code>StartResultCache</code> версией 5.1.8, а <code>setResultCacheKeys</code> — версией 8.6.0. Это нижние границы появления методов, а не гарантия настроек конкретного проекта. Перед переносом примера проверьте версию ядра, редакцию продукта и фактический режим кеширования.</p>\n<h2>Учебный пример с отрицательной веткой</h2>\n<p>Ниже — ограниченный пример. Он не запускает Bitrix, не обращается к базе и не измеряет ответ. Модель только проверяет, что перед изменением шаблона назван полный набор входов кеша. В реальном проекте список нужно подтвердить по компоненту, параметрам и условиям, которые действительно меняют HTML.</p>\n<pre><code>&lt;?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';</code></pre>\n<p>В этом учебном запуске действие блокируется из-за <code>visitor-segment</code>. Это не означает, что именно сегмент замедляет страницу или что он обязательно должен входить в ключ. Это означает только одно: пока неизвестно, меняет ли он результат и где учтён, менять кеш или шаблон рано. Отрицательная ветка защищает от правки, которая выглядит локальной, но меняет данные для разных вариантов запроса.</p>\n<p>Если контракт подтверждён, шаблон можно менять как отдельный обратимый diff. В описании сохраняют старый владелец шаблона, новый владелец и условие возврата. Для воспроизводимого сравнения повторяют не только URL, но и метод, query-параметры, сайт, язык, права или группу, cookie/сегмент, состояние кеша и границу измерения. Сравнение другого URL, другой роли или очищенного кеша не отвечает на исходный вопрос.</p>\n<figure><img src=\"/assets/editorial/2022/bitrix-performance-2022-diagnosis-rollback.svg\" alt=\"Маршрут диагностики Bitrix-страницы: запрос, компонент, кеш, шаблон, проверка и rollback\" loading=\"lazy\" /><figcaption>Схема показывает порядок проверки границ. Она не является профилем живой страницы и не содержит production-таймингов.</figcaption></figure>\n<h2>Симптом → причина → проверка → действие</h2>\n<div class=\"table-scroll\"><table><caption>Диагностическая карта перед изменением Bitrix-страницы</caption><thead><tr><th scope=\"col\">Симптом</th><th scope=\"col\">Вероятная причина</th><th scope=\"col\">Проверка</th><th scope=\"col\">Действие</th></tr></thead><tbody><tr><td>Каталог медленный на одном URL</td><td>Смешаны маршрут и общий разговор о платформе</td><td>Зафиксировать URL, параметры, роль и вариант страницы</td><td>Повторить один и тот же вход</td></tr><tr><td>Очистка кеша временно меняет поведение</td><td>Изменили состояние, но не нашли зависимость</td><td>Сверить ветку кеша и полный список входов</td><td>Не очищать весь кеш как доказательство</td></tr><tr><td>В ключе нет внешнего признака</td><td>HTML зависит от данных, которых нет в контракте</td><td>Проверить, меняет ли признак результат компонента</td><td>Остановить diff и назвать недостающий вход</td></tr><tr><td>Виноватым объявили шаблон</td><td>Видимый файл приняли за источник задержки</td><td>Отделить сбор данных от рендера HTML</td><td>Собрать артефакт именно на нужной границе</td></tr><tr><td>После оптимизации цифра изменилась</td><td>Сравнили разные условия или разные кеш-состояния</td><td>Повторить исходный сценарий и способ измерения</td><td>Оставить только подтверждённый diff</td></tr><tr><td>Нет доступа к профилю или логу</td><td>Гипотезу пытаются выдать за факт</td><td>Записать ограничение и владельца следующего шага</td><td>Не утверждать причину без артефакта</td></tr></tbody></table></div>\n<h2>Как читать компонентный кеш</h2>\n<p>Начните с точки подключения компонента и его параметров. Запишите имя компонента, имя шаблона, время кеширования, режим обновления и все условия, которые меняют данные или HTML. Проверьте, не добавляет ли шаблон зависимость от авторизации, группы пользователя, языка, региона, cookie или внешнего сегмента. Каждый такой признак должен иметь понятное место в контракте. Если он не влияет на результат, это тоже нужно обосновать.</p>\n<p>Затем отделите две задачи. Первая — решить, можно ли повторно использовать результат. Вторая — определить, какие данные должны быть доступны при выводе этого результата. <code>SetResultCacheKeys</code> относится ко второй задаче. Нельзя применять его как универсальную настройку производительности. Если компонент не кешируется или ключ строится неполно, список полей не устранит повторные вычисления.</p>\n<p>Режим «не кешировать» полезен для изоляции гипотезы только при контролируемом тесте и с понятным ограничением. На рабочем трафике он может увеличить число обращений к базе и время выполнения компонента. Ручная очистка кеша также не объясняет причину: она лишь переводит компонент в другую ветку на следующем запросе. После любого такого эксперимента верните исходный режим и зафиксируйте, что именно изменилось.</p>\n<h2>Порядок диагностики</h2>\n<ol><li>Запишите наблюдаемый симптом: маршрут, вариант страницы, условия доступа и шаг, на котором пользователь ждёт. Не добавляйте миллисекунды, SQL или cache hit-rate, если их не измеряли.</li><li>Назначьте четыре границы: request, component, cache и template. Для каждой укажите владельца и один доступный артефакт: код, конфигурацию, лог или разрешённый профиль.</li><li>Составьте cache contract. Перечислите параметры и внешние признаки, которые могут менять HTML. Неизвестный вход пометьте как неизвестный, а не удаляйте из записи.</li><li>Проверьте отрицательный путь. Если нет владельца компонента, недоступен лог, различаются входы или неизвестен внешний признак, остановите изменение и сформулируйте недостающий факт.</li><li>Выберите одну гипотезу и один артефакт, который отличит её от соседней. Не запускайте сразу очистку кеша, переписывание шаблона и изменение SQL.</li><li>Сделайте один обратимый diff. Сохраните старый шаблон, старый режим и точку возврата. Не объединяйте в один шаг изменение ключа, TTL, параметров и структуры HTML.</li><li>Повторите исходный сценарий тем же способом. Отдельно сравните правильность HTML, доступность данных и измеряемый сигнал. Один изменившийся показатель не доказывает улучшение всей цепочки.</li><li>Зафиксируйте результат. Если гипотеза не подтверждена, верните diff и оставьте запись «не подтверждено». Если подтверждена, сохраните evidence и критерий, по которому изменение можно будет проверить снова.</li></ol>\n<h2>Ограничения и случаи остановки</h2>\n<p>Эта схема не заменяет профилирование. Без реального запроса нельзя назвать тяжёлый SQL. Без лога нельзя утверждать длительность PHP. Без повторяемого браузерного сценария нельзя объяснить задержку загрузки скриптов. Документация Bitrix описывает API и режимы платформы, но не знает самописный компонент, его интеграции и данные конкретного сайта.</p>\n<p>Остановитесь, если один и тот же URL получает разный HTML по неописанному условию, если компонент меняет состояние вне своего контракта, если эксперимент запрещён на рабочем трафике или если результат нельзя безопасно откатить. В таком случае полезный итог — не «причина найдена», а точное ограничение: какой факт отсутствует, где его получить и кто отвечает за следующий шаг.</p>\n<p>Учебный код выше нельзя переносить в production как готовую оптимизацию. В нём нет проверки версии ядра, политики персональных данных, реального состава параметров, схемы инвалидирования и нагрузки. Его роль — показать stop condition. Рабочее решение требует локальной проверки и отдельного плана возврата.</p>\n<h2>Проверяемый критерий готовности</h2>\n<p>Диагностика готова к изменению, если другой инженер без устного объяснения может ответить на пять вопросов: какой вход воспроизводят; какой компонент и шаблон рассматривают; какие данные входят в ключ; какой артефакт подтверждает гипотезу; что вернут при отрицательном результате. После diff можно повторить тот же сценарий, увидеть тот же ожидаемый сигнал и однозначно вернуть предыдущее состояние.</p>\n<p>Если на любой вопрос отвечает «обычно Bitrix делает так», работа не готова. Замените общую фразу конкретным неизвестным: «не установлено, влияет ли группа пользователя на HTML», «не подтверждён владелец шаблона» или «нет разрешённого профиля для этого маршрута». Такая формулировка не обещает ускорение. Она делает следующий шаг проверяемым.</p>\n<h2>Проверяемые источники</h2>\n<ul><li><a href=\"https://web.archive.org/web/20220927080127id_/https://dev.1c-bitrix.ru/api_help/main/reference/cbitrixcomponent/startresultcache.php\" target=\"_blank\" rel=\"noopener noreferrer\">1С-Битрикс: CBitrixComponent::StartResultCache (снимок 27.09.2022)</a> — фиксирует ветвление действующего и недействующего кеша, базовые входы и дополнительный идентификатор.</li><li><a href=\"https://web.archive.org/web/20220815073221id_/https://dev.1c-bitrix.ru/api_help/main/reference/cbitrixcomponent/setresultcachekeys.php\" target=\"_blank\" rel=\"noopener noreferrer\">1С-Битрикс: CBitrixComponent::setResultCacheKeys (снимок 15.08.2022)</a> — фиксирует список полей <code>$arResult</code>, сохраняемых для чтения после кеширования.</li><li><a href=\"https://web.archive.org/web/20220629225339id_/https://dev.1c-bitrix.ru/learning/course/?COURSE_ID=43&amp;LESSON_ID=3485\" target=\"_blank\" rel=\"noopener noreferrer\">1С-Битрикс: Кеширование компонентов и меню (снимок 29.06.2022)</a> — фиксирует режимы кеширования и способы обновления кеша на дату материала.</li></ul>"
}