Рефакторинг магазина на Битрикс без остановки продаж: как мерить
Рефакторинг магазина на Битрикс чаще всего ломает не то, что вы правили. Разбираем, что замерить до начала, как выкладывать без простоя и где замеры обманывают.

Самый дорогой сбой при рефакторинге битриксового магазина случается не там, где вы правили код. Ускорили каталог, а на оформлении заказа выросло число ошибок: общий кеш, обработчик события или агент зацепили то, что вы не трогали. Готовых цифр «до и после» здесь нет: у каждого магазина свой каталог и своя нагрузка, а чужие числа только вводят в заблуждение. Вместо них даём протокол замеров и порядок выкладки, при котором продажи не останавливаются.
Что нужно до начала
Материал написан для «1С-Битрикс: Управление сайтом» с модулями sale и catalog на ядре D7, MySQL 8.0 или MariaDB, Nginx и PHP-FPM. Версию платформы смотрите в разделе обновлений админки. В старых редакциях пункты меню называются иначе.
- SSH-доступ и право менять конфиги Nginx и MySQL;
- тестовая копия на базе сопоставимого размера: на пустой базе планы запросов другие;
- свежий бэкап, из которого вы уже хотя бы раз восстанавливались.
Фиксируем «до»
Без базовой линии «стало быстрее» остаётся ощущением. Мерьте минимум неделю, чтобы поймать пики и акции, и записывайте условия: железо, число товаров и торговых предложений, параллельность, прогретость кеша.
| Показатель | Чем мерить | Подвох |
|---|---|---|
| p50 и p95 времени ответа по каталогу, карточке, корзине, оформлению | Лог Nginx с $request_time | Среднее прячет хвост, который чувствуют покупатели |
| Число и время SQL-запросов на хит | Монитор производительности в разделе «Настройки → Производительность» или параметр show_sql_stat=Y под администратором (уточните по документации своей версии) | Под администратором цифры выше, чем у покупателя |
| Прогретость кеша | Два хита подряд на одну страницу | На втором хите запросов к базе должно быть заметно меньше |
| Медленные запросы | Slow log MySQL и pt-query-digest | Слишком низкий порог раздувает лог |
| Занятые воркеры PHP-FPM | pm.status_path | Закройте страницу статуса от внешнего доступа |
Лог с временем ответа в конфиге Nginx, внутри блока http:
# Время ответа PHP и полное время запроса; request_time стоит последним полем
log_format timing '$remote_addr [$time_local] "$request" $status '
'$upstream_response_time $request_time';
access_log /var/log/nginx/timing.log timing;
p50 и p95 по каталогу из этого лога:
# Последнее поле строки — $request_time
grep ' /catalog/' /var/log/nginx/timing.log \\
| awk '{print $NF}' | sort -n \\
| awk '{a[NR]=$1} END {print "p50:", a[int(NR*0.5)+1], "p95:", a[int(NR*0.95)+1]}'
Slow log включается без перезапуска. Настройка действует на новые соединения, а после замера порог стоит вернуть:
-- MySQL 8.0 / MariaDB
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
SET GLOBAL long_query_time = 0.5;
SET GLOBAL slow_query_log = 'ON';
Разбор лога: pt-query-digest /var/log/mysql/slow.log > digest.txt (Percona Toolkit). Он группирует запросы и показывает, какие съели больше всего времени.
Почему правки в Битриксе растекаются
Результат компонента лежит в кеше вместе с HTML, а привязан к тегам. Любое изменение элемента инфоблока сбрасывает кеш всех компонентов, подписанных на этот инфоблок. Отсюда три следствия.
result_modifier.phpвыполняется при построении кеша, а не на каждом хите. Поправили шаблон, а покупатели видят старый HTML, пока не истечётCACHE_TIMEили кеш не сбросят вручную.- Частые правки каталога, например обмен с 1С, постоянно сбрасывают теги. Ускоренный шаблон может не дать выигрыша, если кеш живёт минуты.
- Полный сброс кеша в рабочее время запускает одновременную пересборку всех компонентов. База получает сразу всю нагрузку, которую кеш обычно гасит (cache stampede).
Рефакторинг без замеров — просто правка кода. С замерами это эксперимент, который можно откатить.
Порядок выкладки без остановки
- Разверните тестовую копию. Обезличьте данные покупателей, отключите почтовые события, обмен с 1С и боевые платёжные системы. Письма клиентам из тестовой копии — частая и неприятная ошибка.
- Меняйте один узел за раз. После каждого шага повторяйте замеры из таблицы при тех же условиях.
- Включайте новый шаблон сначала для тестовой группы пользователей. Ветвление по группе пишется в шаблоне, а в компоненте нужен
CACHE_GROUPS=Y, иначе кеш группы смешается с общим. Цена: кеша станет больше. - Выкладывайте код из каталога
/localчерез релизные каталоги и переключение симлинка. После переключения сделайте graceful reload PHP-FPM, иначе opcache может отдавать старые файлы. - Индексы добавляйте онлайн: для InnoDB подойдёт
ALTER TABLEсALGORITHM=INPLACE, LOCK=NONE. Индексы на таблицах ядра называйте со своим префиксом и записывайте в миграции: обновления платформы о них не знают. - Выкладывайте в часы минимальных продаж по вашей аналитике. Порог отката, например рост 5xx на оформлении, задайте заранее, а не по ощущению.
После выкладки прогрейте ключевые страницы по очереди обычными запросами. Параллельный прогрев сам создаёт всплеск нагрузки.
Горячие зоны магазина
| Зона | Что обычно дорого | Как менять безопасно |
|---|---|---|
Каталог и карточка (catalog.section, catalog.element) | Запросы цен и остатков в цикле из шаблона: по запросу на товар | Собрать данные одним пакетом до цикла. Сверить итоговые цены со старыми на товарах с разными типами цен и скидками |
Умный фильтр (catalog.smart.filter) | Выборка по свойствам без фасетного индекса | Включить и пересобрать фасетный индекс ночью: пересборка нагружает базу |
Корзина и оформление (sale.basket.basket, sale.order.ajax) | Свои обработчики событий заказа, правила скидок | Трогать последними и только через тестовую группу |
| Агенты | По умолчанию выполняются в запросах посетителей | Переносить на cron по документации. Без настроенного cron агенты перестанут выполняться |
Где подход ломается
- Композитный сайт отдаёт страницы анонимам, минуя PHP. Замер на нём не покажет вашу оптимизацию, поэтому мерьте отдельно с композитом, без него и под авторизованным покупателем.
- Тестовая копия с урезанной базой врёт: индекс, который не нужен на 10 000 товаров, нужен на миллионе.
- Холодный кеш «до» и тёплый «после» несопоставимы. Сравнивайте в одинаковом состоянии.
- Ошибка в ценах не даёт сбоев: страница отвечает 200, а сумма другая. Проверяйте суммы заказов, а не статус-коды.
- Откат кода не откатывает данные. Новый индекс обычно безопасен, правки данных возвращаются только из бэкапа.
Что делать дальше
На этой неделе включите логи из статьи и соберите замеры, не меняя ни строчки кода. Затем возьмите зону с худшим p95 и сделайте её отдельным релизом. В проде следите за четырьмя показателями: p95 оформления заказа, доля 5xx, число медленных запросов за сутки, занятые воркеры PHP-FPM. Сброс кеша при обмене с 1С — отдельная тема, здесь её не разбираем.
Теги кеша. Метки на закешированном результате, например ID инфоблока. Когда данные с такой меткой меняются, кеш сбрасывается.
p95. Время, быстрее которого отвечает 95% запросов. Показывает «хвост», который реально чувствуют покупатели.
Защитник прав потребителей: Досудебные претензии на возврат товара со ссылками на ЗоЗПП.
Спросить за 15 ₽Источники: 1С-Битрикс: документация для разработчиков, MySQL Reference Manual: The Slow Query Log
Частые вопросы
Можно ли рефакторить магазин на Битриксе, не останавливая продажи?
А если у меня другая версия Битрикса или старое ядро?
А если после выкладки стало хуже или не сработало?
Можно ли сбрасывать весь кеш в рабочее время?
Какие значения считать успехом рефакторинга?
Что чаще всего забывают при выкладке в прод?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.