Битрикс тормозит: с чего начать диагностику и как не гадать
Тормоза Битрикс почти всегда складываются из трёх слоёв: окружение (PHP, OPcache, память), код (тяжёлые GetList и лишние выборки) и инфраструктура (БД, обмен с 1С). Начинаем с замеров — Монитор производительности и bitrix_server_test.php, затем правим настройки PHP 8.2 и OPcache, включаем логирование через PSR-3 и только после этого трогаем запросы. Так вы не гадаете, а видите, где именно теряются миллисекунды.
«Сайт тормозит» — это не диагноз, а жалоба. Она не говорит, где искать: страница может отдавать HTML за 200 мс, но ждать ответа от 1С, или собираться из кеша мгновенно, но упираться в медленный диск. Пока нет замера, любая правка — ставка на удачу: включили композитный кеш, а тормозил обмен; подняли memory_limit, а узким местом был запрос к b_iblock_element_prop_s*. Прежде чем что-то менять, нужно разложить жалобу на измеримые величины и понять, какой слой даёт задержку.
Диагностику мы ведём по трём слоям: окружение (PHP, OPcache, веб-сервер, диск), код (запросы, выборки, шаблоны) и инфраструктура (БД, обмен с 1С, внешние сервисы). Порядок именно такой: сначала дешёвые проверки окружения, потом код, потом интеграции. Окружение даёт грубые, но частые провалы. Инфраструктурные задержки ищутся дороже и дольше. Замер TTFB и времени полной отдачи страницы отделяет серверную часть от клиентской. Если TTFB в норме, а страница «тяжёлая» — копать надо в вёрстке и статике, а не в PHP.
- Окружение — признак: стабильно высокий TTFB на всех страницах, включая простые; проверяем версию PHP, OPcache, лимиты памяти, диск.
- Код — признак: одни страницы быстрые, другие медленные; смотрим тяжёлые выборки, шаблоны, кеширование компонентов.
- Инфраструктура — признак: просадки привязаны к расписанию или к моменту синхронизации; проверяем MySQL, обмен с 1С, внешние API.
| Симптом | Вероятный слой | Первый инструмент |
|---|---|---|
| Высокий TTFB на всех страницах | Окружение | Замер TTFB, проверка OPcache |
| Отдельные страницы медленные | Код | Монитор производительности |
| Пики в часы обмена | Инфраструктура | Логи обмена с 1С |
| Долгий ответ API-метода | Код | Время ответа метода |
Высокий TTFB держится на всех страницах одинаково? Начинайте с окружения: это быстрее всего проверить и отсечь. Проседают отдельные страницы, а остальные отдаются нормально — причина почти всегда в коде конкретного компонента или шаблона. И только если задержки привязаны к расписанию, к моменту синхронизации с 1С или к пиковой нагрузке на базу, есть смысл идти в инфраструктуру.
Профайлинг Bitrix: монитор производительности и bitrix_server_test.php
Штатный профайлинг в Bitrix закрывает большинство вопросов, с которыми обычно идут за XHProf или Blackfire. Монитор производительности и bitrix_server_test.php дают две разные картины: первый показывает, что происходит внутри приложения на реальных страницах, второй проверяет, соответствует ли окружение требованиям платформы. Вместе они позволяют отделить код от конфигурации сервера ещё до того, как вы поставите внешний инструмент.
Когда этого достаточно? Если сайт тормозит на конкретных страницах, при пиковых нагрузках или после обновления модуля — начните с Монитора. Если тормозит всё и сразу, одинаково на всех URL, — сначала bitrix_server_test.php: возможно, узкое место в PHP, OPcache или лимитах памяти, и никакой профайлер кода вам не поможет. Внешние инструменты подключайте, когда нужно разобрать конкретный вызов или построить flame graph по одному запросу.
Где в админке открыть монитор производительности и что он измеряет
Модуль «Монитор производительности» лежит в разделе Настройки > Производительность > Панель производительности. Ему нужно накопить статистику: он снимает замеры на реальных хитах, поэтому первые данные появляются не мгновенно, а по мере трафика. Для тестового контура это значит, что нужно сначала прогнать типичные сценарии — карточку товара, каталог, корзину, — а уже потом смотреть отчёт.
Что измеряется: время генерации страницы, количество и суммарное время SQL-запросов, объём включённых компонентов, попадания и промахи кеша, потребление памяти PHP. Отдельно показывается индекс производительности в «попугаях» — сводная оценка, по которой удобно сравнивать состояние сайта до и после правок. Именно этот индекс имеет смысл держать под наблюдением при регулярной оптимизации, а не гоняться за абсолютным значением.
Как читать отчёт монитора: какие показатели указывают на окружение, а какие на код
Первый раздел, на который стоит смотреть, — распределение времени между PHP и SQL. Если доля SQL стабильно высокая и это не связано с конкретной страницей, проблема чаще в окружении: диск, кеш MySQL, отсутствие индексов. Если высокая доля PHP при небольшом числе запросов — ищите в коде: тяжёлые циклы, повторные вызовы API, неэффективные выборки CIBlockElement::GetList.
Разделяйте сигналы так:
- Много SQL-запросов на страницу при малом времени PHP — узкое место в слое данных или в компонентах, которые дёргают выборки повторно.
- Высокое потребление памяти при нормальном времени — проблема в структуре данных или в размере выборок, а не в запросах.
- Промахи кеша на стабильных страницах — либо кеш сбрасывается слишком часто, либо ключи кеширования зависят от изменчивых параметров.
- Ровно высокое время на всех страницах без явного лидера — смотрите окружение: OPcache, PHP-FPM, диск.
Смотрите не на один замер, а на динамику: Монитор агрегирует данные, и разовые всплески от фоновых задач не должны сбивать картину. Сравнивайте медианные значения по группе однотипных страниц, а не единичные пики.
- Запустить
bitrix_server_test.phpиз корня сайта и сверить окружение с требованиями Битрикс: версии Apache 2.4.x или nginx 1.16.x и выше, PHP, настройки OPcache,mbstring.func_overload,default_charset=UTF-8,memory_limit. - Сопоставить вывод теста с фактическими настройками на боевом сервере — тест может запускаться в другом пуле PHP-FPM.
- Отметить расхождения и устранить их до следующего замера Монитора, чтобы не сравнивать разные окружения.
Настройка OPcache и PHP 8.2 для Битрикс
OPcache хранит скомпилированный байткод в разделяемой памяти процесса. Пока PHP-файл не изменён, интерпретатор не читает его с диска и не компилирует заново: готовый опкод берётся из памяти. На Битриксе это заметно уже на «холодном» ядре — сотни подключаемых файлов на каждый хит, и без кеша каждый запрос платит за их разбор. На PHP 8.2 эффект складывается с оптимизациями самого интерпретатора, поэтому окружение — самый быстрый выигрыш до любых правок кода: вы не трогаете логику, не переписываете компоненты, а просто перестаёте компилировать одно и то же на каждом запросе.
Порядок действий такой: сначала проверить, что OPcache вообще включён и работает в режиме, а не формально. Дальше — выставить параметры под размер каталога и частоту деплоя. И только потом идти в профайлер за узкими местами в коде. Если кеш опкода не настроен, любые замеры времени выполнения будут искажены: вы оптимизируете то, что и так упирается в пересборку скриптов.
Какие параметры opcache включать и почему validate_timestamps должен быть On
В opcache.ini первым делом включается сам модуль — opcache.enable=1, и отдельно для CLI, если гоняете скрипты обмена и кроны: opcache.enable_cli по умолчанию выключен, и на CLI-задачах кеш не работает. Дальше ключевой момент — opcache.validate_timestamps. Его рекомендуемое значение — On. Соблазн поставить Off понятен: тогда PHP вообще не проверяет mtime файлов и не инвалидирует кеш, это чуть быстрее. Но при Off правка файла на сервере не подхватится, пока вы не перезапустите PHP-FPM или явно не сбросите кеш.
Для Битрикса с его обновлениями модулей, патчами ядра и правками шаблонов это прямой путь к «почему на сервере старый код». Оставляем On, а частоту проверки регулируем opcache.revalidate_freq. Рекомендуемое значение — 0: проверять при каждом запросе. Так вы не ловите рассинхрон между деплоем и кешем, а накладные расходы на stat при включённом OPcache малы. Компромиссный вариант — revalidate_freq=2, если деплой частый и хочется срезать лишние stat-вызовы. Тогда держите в голове окно в пару секунд, когда старый опкод ещё жив.
Что делать с memory_limit и mbstring.func_overload на PHP 8.2
memory_limit меняется в php.ini или через ini_set("memory_limit", "256M") в рантайме. Официальная документация Битрикса приводит пример со 256M; в сообществе для проектов с большим каталогом и тяжёлым обменом чаще ориентируются на 512M. Ориентир — 512M для нагруженных проектов, 256M — базовый пример из документации. Конфигурация с 128M на PHP 8.2 для развивающегося проекта проблемная: обмен с 1С, генерация отчётов и экспорт каталога легко упираются в лимит и падают по памяти. Поднимайте лимит с запасом и следите за реальным потреблением, а не за красивым числом.
Отдельная история — mbstring.func_overload. На PHP 8.2 этой директивы больше нет: она удалена из самого расширения mbstring. В конфиге она должна быть удалена, а не выставлена в 0. Строка mbstring.func_overload=0, оставшаяся от старых конфигов, на PHP 8.2 даёт предупреждение при старте и в лучшем случае игнорируется. Убирайте её из php.ini целиком. Заодно проверьте default_charset — должно быть UTF-8, иначе получите рассинхрон кодировок между базой, шаблонами и ответом сервера.
; opcache.ini
opcache.enable=1
opcache.enable_cli=1
opcache.validate_timestamps=On
opcache.revalidate_freq=0
opcache.max_accelerated_files=100000
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.save_comments=1
; php.ini — секция mbstring и ресурсов
; mbstring.func_overload — настройка должна быть удалена
default_charset=UTF-8
memory_limit=512M
file_uploads=On| Параметр | Рекомендуемое значение | На что влияет |
|---|---|---|
opcache.max_accelerated_files |
100000 |
Число файлов в кеше опкода; на большом каталоге и ядре Битрикса малое значение вытесняет скрипты |
opcache.revalidate_freq |
0 |
Как часто проверять mtime файлов; при 0 — при каждом запросе, деплой подхватывается сразу |
memory_limit |
256M–512M |
Потолок памяти на запрос; обмен с 1С и экспорт каталога требуют запаса |
default_charset |
UTF-8 |
Кодировка ответа и внутренних строк; рассинхрон с базой ломает вывод |
Для типового проекта с каталогом до десятков тысяч SKU хватает значений из таблицы в базовом варианте. Если каталог крупнее и обмен идёт часто, поднимайте memory_limit к 512M и увеличивайте opcache.memory_consumption — иначе кеш будет вытеснять опкод раньше, чем он понадобится.
mbstring.func_overload на PHP 8.2 нужно именно удалить из конфигурации, а не выставлять в 0. Директивы в расширении mbstring больше нет: строка в php.ini вызовет предупреждение при старте PHP. Если оставить её в надежде «обнулить перегрузку», поведение функций работы со строками не изменится, а конфиг будет содержать мёртвую настройку. Уберите строку целиком и проверьте, что default_charset стоит в UTF-8 — иначе получите битую кодировку в выводе.
Медленная работа сайта Битрикс: где искать узкое место в коде
Монитор производительности показывает, что страница каталога собирается 1,8 секунды, OPcache настроен, база отвечает быстро — а TTFB всё равно высокий. Дальше начинается самое неприятное: метрика есть, а виновника нет. Общие замеры говорят «где-то в PHP», но не говорят «в каком файле». Чтобы дойти до конкретного вызова, нужно сузить область поиска: сначала определить, на каком шаге страницы время уходит, потом — какой компонент этот шаг обслуживает, и только потом открывать код. Профайлер на этом этапе уже не помогает: он показывает агрегаты по функциям, а нам нужен файл и строка.
Практический путь — идти от подозрительного участка шаблона к его обработчику, добавляя точечные замеры через microtime(true) или логгер, и сравнивать время до и после каждого подозрительного вызова. Так узкое место находится за один-два прохода, а не за неделю перебора.
- Тяжёлые выборки
CIBlockElement::GetListбез ограничения полей и без кеша — на каталогах от 20k SKU дают основной вклад в TTFB. - Циклы по элементам с отдельным запросом на каждый: свойства, цены, остатки, торговые предложения — классический N+1.
- Компоненты без
$arParams['CACHE_TYPE']или с малым временем кеширования, пересобирающие выдачу на каждом хите. - Собственные обработчики событий на
OnBeforeIBlockElementUpdateи подобных, которые выполняются на публичных страницах. - Тяжёлые
includeиrequireв шаблоне, подключающие модули и файлы, не нужные на этой странице.
Правка файлов ядра в /bitrix/modules/ как «быстрый фикс» — самый дорогой способ ускорить сайт. Любое обновление модуля затирает изменения без предупреждения, вернуть их можно только из бэкапа, а поведение прода после апдейта становится непредсказуемым. Отладка в ядре запрещена не из-за стиля: файлы модулей не версионируются в вашем репозитории и не покрыты тестами.
Вместо этого используйте штатные точки расширения: обработчики событий, OnBeforeIBlockElementUpdate и другие, собственные компоненты в /local/components/, настройки через .settings.php. Если правка ядра кажется единственным выходом — сначала проверьте, нет ли штатного события или настройки под вашу задачу.
Логирование в Битриксе: AddMessage2Log, PSR-3 и стек вызовов
Когда Монитор производительности показывает всплеск на конкретном хите, а OPcache и база отработали штатно, дальше приходится отвечать на другой вопрос: что именно в коде выполнилось лишнего и в каком порядке. Тут и начинается разница между «накидать AddMessage2Log по подозрительным местам» и нормальным логированием. Первое быстро превращается в мешанину из строк без уровней и контекста, которую через неделю невозможно читать; второе даёт уровни, формат и стек вызовов, по которому видно цепочку до виновника. Переход на PSR-3-логгеры окупается ровно тогда, когда диагностикой занимается не один человек и не один раз: на проектах с обменом 1С, cron-задачами и агентами, где ошибка воспроизводится не ежедневно. Для разового «посмотреть, что тут происходит» хватит и старой функции — не надо тянуть инфраструктуру ради одного запроса. Но как только логи становятся рабочим инструментом, а не разовым приёмом, разница в скорости поиска причины становится заметной.
AddMessage2Log: константа LOG_FILENAME и логгер в .settings.php с версии 23.500.0
Функция AddMessage2Log — исторический способ записи в файл, и у неё есть жёсткое условие: до вызова должна быть определена константа LOG_FILENAME с путём к файлу. Без неё вызов молча ничего не сделает — самая частая причина «логи вроде пишу, а файл пустой». Определять её надо в /bitrix/php_interface/dbconn.php или в файле, который подключается до первого вызова. Начиная с версии 23.500.0 в .settings.php можно указать логгер, которому уходит вывод AddMessage2Log, — и это ключевой момент для поэтапного перехода. У вас может быть сотня вызовов по коду, и переписывать их сразу никто не станет. Вместо этого вы задаёте в настройках один логгер, и старые вызовы начинают идти через него — с уровнями, форматтером и записью в нужное место. Дальше новые места логируются уже через PSR-3, а старые постепенно вымываются при рефакторинге. Смысл в том, чтобы не ломать работающий код ради красивой архитектуры, а получить единый поток логов сразу.
Штатные логгеры Bitrix: FileLogger, SysLogger, EventLogger и выбор формата
Базовый класс \Bitrix\Main\Diag\Logger реализует \Psr\Log\LoggerInterface, а конкретные реализации отличаются только приёмником. \Bitrix\Main\Diag\FileLogger пишет в файл — это рабочий вариант для отладки на dev-контуре и для разбора инцидента. \Bitrix\Main\Diag\SysLogger отправляет сообщения в системный журнал, что удобно, когда логи собирает syslog или journald на сервере. \Bitrix\Main\Diag\EventLogger пишет в таблицу b_event_log — вариант для тех случаев, когда логи нужно смотреть из админки, но помните: запись в базу под нагрузкой — это дополнительная нагрузка на ту же базу, которую вы диагностируете.
Формат задаётся через \Bitrix\Main\Diag\LogFormatter и интерфейс LogFormatterInterface; с версии 25.300.0 доступен \Bitrix\Main\Diag\JsonLinesFormatter — по строке JSON на сообщение, что удобно для последующего разбора скриптом. Уровни берутся из \Psr\Log\LogLevel::* — от emergency до debug. Для внедрения логгера в существующий класс пригодится \Psr\Log\LoggerAwareInterface и \Psr\Log\LoggerAwareTrait, а создать логгер по идентификатору можно через \Bitrix\Main\Diag\Logger::create('logger.id', [$this]).
use Bitrix\Main\Diag\FileLogger;
use Bitrix\Main\Diag\Helper;
use Psr\Log\LogLevel;
$logPath = $_SERVER['DOCUMENT_ROOT'] . '/local/log/app.log';
// 0 — без ограничения размера, иначе по умолчанию 1 Мб
$maxLogSize = 0;
$logger = new FileLogger($logPath, $maxLogSize);
$logger->setLevel(LogLevel::ERROR);
// аргументы в стеке не показываем, глубину ограничиваем
$logger->error(
"{date} - {host}\n{trace}{delimiter}\n",
[
'trace' => Helper::getBackTrace(6, DEBUG_BACKTRACE_IGNORE_ARGS, 3),
]
);| Логгер | Куда пишет | Когда выбирать |
|---|---|---|
| FileLogger | файл на диске | отладка и разбор инцидента |
| SysLogger | системный журнал | централизованный сбор на сервере |
| EventLogger | таблица b_event_log | просмотр логов из админки |
Для регулярной диагностики узких мест на боевом контуре чаще подходит FileLogger с уровнем ERROR и отдельным файлом под задачу, а EventLogger стоит держать для редких административных событий, чтобы не грузить базу под нагрузкой.
По умолчанию максимальный размер лога — 1 Мб. Передайте $maxLogSize = 0, чтобы снять ограничение, но тогда следите за ротацией файла самостоятельно.
Тяжёлые запросы: CIBlockElement::GetList и ключи, которые больше не работают
Фильтр по ключу CHECK_PERMISSIONS или TASKSTATUS выглядит рабочим: страница отдаёт нужный набор элементов, ошибок в логе нет. Но запрос при этом идёт по всей таблице b_iblock_element, а условие отсекается уже в PHP после выборки. На каталоге в десятки тысяч SKU это даёт секунды на страницу. В профайлере их не видно как отдельный «тяжёлый» вызов — время уходит внутрь GetList. Начиная с версии 20.5.0 модуля «Информационные блоки» метод CIBlockElement::GetList не обрабатывает эти ключи вовсе, поэтому старые сниппеты фильтрации перестали ограничивать выборку. Подход к выборкам приходится строить заново: не надеяться на «магические» ключи, а явно описывать, какие поля нужны и по какому условию идёт отбор.
Что изменилось в CIBlockElement::GetList с версии 20.5.0 модуля iblock
Раньше часть ключей в arFilter метод понимал как служебные и сам преобразовывал в условия SQL. С версии 20.5.0 модуля «Информационные блоки» поддержка ключей CHECK_PERMISSIONS и TASKSTATUS убрана: метод их игнорирует. Синтаксически вызов остаётся валидным — массив фильтра принимается, ошибки не возникает, — но условие в SQL не попадает.
Практический эффект: код, который годами работал и «фильтровал по правам», теперь возвращает больше элементов, чем ожидалось. Дальше два варианта. Либо разработчик замечает, что выборка выросла, и добавляет отсечение в PHP — что не спасает от чтения лишних строк из базы. Либо не замечает: страница работает, но GetList стабильно тянет всю таблицу и тормозит на росте каталога.
Проверить, использует ли проект устаревшие ключи, стоит поиском по коду — grep -rn "CHECK_PERMISSIONS\|TASKSTATUS" по /bitrix/php_interface и шаблонам компонентов. Найденные места нужно переписать на явный фильтр по ACTIVE, IBLOCK_ID и тем полям, по которым реально идёт отбор.
Как сортировка автоматически попадает в arSelectFields и arGroupBy и почему это важно
Поля, указанные в arOrder, метод добавляет в arSelectFields автоматически — а если задана группировка, то в arGroupBy. Это значит, что «сортировка по SORT» на деле расширяет список выбираемых полей и, при группировке, участвует в GROUP BY. Пока полей в сортировке одно-два, это незаметно; когда в arOrder накапливается пяток полей «на всякий случай», запрос тянет лишние колонки и группирует по ним же.
Отсюда правило: в arOrder - только то, по чему действительно сортируем. Всё остальное явно перечисляем в arSelectFields, а не оставляем «на авось». Если выборка идёт с группировкой, каждое лишнее поле в сортировке удорожает GROUP BY. И наоборот: явный список нужных полей в arSelectFields без группировки даёт базе шанс использовать индекс и не читать широкие строки.
Второй момент - arGroupBy при пустом значении. Ниже - пример, как выглядит явный вызов вместо устаревших ключей.
<?php
// Явная выборка вместо устаревших ключей CHECK_PERMISSIONS и TASKSTATUS
$arOrder = ['SORT' => 'ASC', 'ID' => 'ASC']; // только то, по чему реально сортируем
$arFilter = [
'IBLOCK_ID' => CATALOG_IBLOCK_ID, // замените на ID вашего инфоблока
'ACTIVE' => 'Y',
'ACTIVE_DATE' => 'Y',
];
$arSelectFields = ['ID', 'NAME', 'CODE', 'SORT', 'PREVIEW_PICTURE', 'DETAIL_PAGE_URL'];
$rsElements = CIBlockElement::GetList(
$arOrder,
$arFilter,
false, // arGroupBy: false, если группировка не нужна
false, // arNavStartParams: без постранички
$arSelectFields
);
while ($arElement = $rsElements->Fetch()) {
// обработка элемента
}Что происходит: неподдерживаемые ключи в фильтре не вызывают ошибки - вызов GetList отрабатывает штатно, страница отдаёт результат. Почему это опасно: условие не попадает в SQL, выборка идёт по всей таблице b_iblock_element, а отсечение происходит уже в PHP. В профайлере это выглядит как «нормальный» вызов без всплеска, поэтому проблему легко пропустить. Как обойти: убрать устаревшие ключи из arFilter, задать отбор по IBLOCK_ID, ACTIVE и конкретным полям, а нужные колонки перечислить в arSelectFields явно.
Как ускорить обмен с 1С, если сайт тормозит именно в момент синхронизации
Просадка TTFB, которая повторяется по расписанию - в 2:00, в 9:15, в 13:30 - почти всегда указывает не на фронтенд и не на кеш компонентов. Если Монитор производительности показывает ровный график в течение дня и резкий пик в определённые часы, а страница отдаёт тот же HTML, что и всегда, значит нагрузку создаёт фоновый процесс. Самый частый такой процесс на Bitrix-проекте с интеграцией - обмен с 1С.
Почему это важно поймать именно на этапе диагностики: обмен - это не одна операция, а сотни транзакций. Каждая выгрузка номенклатуры, цен, остатков или заказов проходит через CIBlockElement::GetList, CIBlockElement::Add, CIBlockElement::Update и запись в b_catalog_price. Пока сессия обмена активна, MySQL занят блокировками, а веб-сервер ждёт освобождения соединений из пула. Поэтому тормозит не только админка, но и публичный каталог - он стоит в той же очереди за соединением.
- Проверить журнал событий:
Настройки > Инструменты > Журнал событий, отфильтровать по модулямcatalog,iblock,saleи по времени пика. - Найти время старта сессии обмена - в журнале это запись о запуске агента или о вызове скрипта обмена, обычно с указанием источника.
- Замерить длительность шагов: обмен идёт порциями, и по логу видно, какая именно порция (товары, цены, остатки, заказы) съедает основное время.
- Сопоставить окно обмена с графиком TTFB из Монитора производительности - совпадение по минутам подтверждает гипотезу.
Если локализация подтвердила, что дело в обмене, смотрите отдельный разбор причин тормозов обмена 1С в блоге: там про индексы, порционный импорт и события на OnAfterIBlockElementUpdate.
Что проверить после оптимизации: контрольные замеры
Оптимизация без контрольного замера - это вера, а не инженерия. Монитор производительности показывал 1,8 секунды на странице каталога, вы включили OPcache, поправили индексы, переписали тяжелый CIBlockElement::GetList - и что дальше? Ощущение «вроде быстрее» ничего не доказывает: на прогретом кеше любая страница отдаётся быстро, а через час, когда кеш сбросится под нагрузкой или обмен с 1С наложит блокировки, картина вернётся к исходной. Хуже того, часть правок может дать локальный выигрыш и общий проигрыш: агрессивное кеширование компонента ускоряет выдачу, но усложняет инвалидацию и приводит к устаревшим данным в каталоге.
Поэтому после каждого изменения мы возвращаемся к той же точке, с которой начинали диагностику, и повторяем замер по неизменному сценарию.
Смысл контрольного замера - не получить красивое число, а зафиксировать устойчивое улучшение, которое воспроизводится на нескольких прогонах и на разных страницах. Без этого вы не отличите реальный эффект от разовой удачи и не сможете сказать руководителю, что именно изменилось.
- Повторить сценарий из первой секции на тех же страницах и в то же время суток. Возьмите ровно те URL, которые профайлили на этапе диагностики, и прогоните их в тот же временной интервал: если замер делался в 11:00, не проверяйте результат в 20:00, когда фоновые задачи и обмен с 1С уже отработали. Сценарий должен быть воспроизводимым - иначе сравнение теряет смысл.
- Сравнить показатели Монитора производительности и TTFB до и после. Откройте Настройки > Производительность > Панель производительности, снимите текущие значения времени генерации страницы, числа запросов к базе и объёма выборки, а TTFB замерьте тем же инструментом, что и раньше. Сравнивайте не абсолют, а дельту по каждому показателю - она и покажет, где правка сработала, а где нет.
Читайте также: Как ускорить Битрикс: композит, кэширование и настройка сервера, Тормозит обмен 1С с Битрикс: как замерить через события и найти узкое место.
Подробнее об услуге: аудит производительности и безопасности.
Частые вопросы
Почему CIBlockElement::GetList стал медленнее после обновления модуля до 20.5.0?
Деградация выборок CIBlockElement::GetList - типичный признак того, что узкое место сместилось в код или в слой данных, а не в окружение. Проверьте долю SQL и число запросов на страницу в Мониторе производительности: если запросов много при небольшом времени PHP, ищите повторные выборки и отсутствие индексов, а не саму версию модуля.
Как включить логирование SQL-запросов в Битрикс без правки ядра?
Логирование подключается через PSR-3, без вмешательства в ядро. Начинать стоит после того, как сняты базовые замеры TTFB и времени ответа ключевых методов, иначе по логам не с чем будет сравнивать.
Что показывает Монитор производительности и какие значения считать нормой?
Монитор измеряет время генерации страницы, количество и суммарное время SQL-запросов, объём включённых компонентов, попадания и промахи кеша и потребление памяти PHP, а также выводит индекс производительности в «попугаях». Ориентироваться нужно не на абсолютное значение, а на динамику: сравнивайте медианы по группе однотипных страниц до и после правок, а не единичные пики.
Можно ли ускорить Битрикс только настройками сервера, без переписывания кода?
Да, если узкое место в окружении: стабильно высокий TTFB на всех страницах, включая простые, лечится настройками PHP 8.2, OPcache, PHP-FPM и диска. Когда проседают отдельные страницы, а остальные отдаются нормально, причина в коде конкретного компонента или шаблона, и настройками сервера её не закрыть.
Как найти узкое место в обмене с 1С, если сайт тормозит именно в момент синхронизации?
Привязка просадок к расписанию или к моменту синхронизации указывает на инфраструктурный слой - смотрите логи обмена с 1С и состояние MySQL. Перед этим зафиксируйте задержки обмена как базовую линию, иначе не отличите эффект от правок от обычного затишья в нагрузке.