Play
online · 30 мин
Туториалы 18 мин чтения 11.09.2026

Как ускорить Битрикс: композит, кэширование и настройка сервера

Каталог на 30 тысяч SKU грузится 2–4 секунды, а админка бесит менеджеров? В 90% случаев виноваты не «Битрикс вообще», а пара конкретных мест — тяжёлые запросы к MySQL, отсутствие кеша компонентов и неверные настройки сервера. Разбираем, как найти узкое место за пару часов и ускорить сайт за день.

Почему Битрикс медленно работает: где искать узкое место

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

Практика показывает: причина почти всегда лежит в одной из четырёх плоскостей.

  • Тяжёлые запросы к MySQL — неиндексированные выборки по свойствам, N+1 в циклах компонентов, JOIN'ы по таблицам без ключей.
  • Отсутствие кеша компонентов — компонент вызывается с CACHE_TYPE => "N" или кеш сбрасывается на каждом хите из-за неверного CACHE_GROUPS.
  • Не включён композит — статика отдаётся через полный прогон PHP, хотя могла бы уходить из html_pages.
  • Слабые настройки PHP и MySQL — маленький memory_limit, дефолтный innodb_buffer_pool_size, отсутствие opcache.

Соблазн «оптимизировать вслепую» здесь очень велик: нагуглить чек-лист, включить всё подряд и надеяться. Так делать нельзя — вы не узнаете, что именно помогло, а что сломало корзину или фильтр. Сначала замер, потом правка.

Порядок диагностики, к которому мы пришли на десятках проектов:

  1. Снять замер в панели производительности — зафиксировать время генерации, число запросов, память.
  2. Посмотреть список медленных запросов MySQL — включить slow_query_log и отсортировать по Time.
  3. Проверить, кешируются ли ключевые компоненты — catalog.section, catalog.element, news.list.
  4. Проверить, включён ли композитный режим для страниц каталога и карточек.
  5. Проверить настройки PHP и MySQL — opcache, memory_limit, innodb_buffer_pool_size, thread_pool_size.

Панель производительности (Настройки → Производительность → Панель производительности) — это не просто «сколько миллисекунд». Смотрите на три числа: время генерации страницы, количество запросов к БД и пиковое потребление памяти. Первое говорит о пользовательском опыте, второе — о нагрузке на MySQL, третье — о близости к лимиту PHP.

Абсолютные цифры обманчивы: 800 мс на dev-машине и на боевом сервере под нагрузкой — это два разных мира. Панель поэтому и предлагает сравнение с эталонной системой. Важна не сама цифра, а отклонение от нормы. Если ваш каталог считает страницу заметно дольше эталона, узкое место уже локализовано.

Отдельный тревожный сигнал — 200+ запросов на страницу каталога. Это почти всегда означает одно: компонент крутит цикл по элементам и внутри дёргает свойства, цены, скидки отдельными запросами. Лечится не «оптимизацией MySQL», а переписыванием выборки через getList с select нужных полей и включённым управляемым кешем — об этом в разделе про CPHPCache.

Композитный сайт Битрикс: как включить и настроить

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

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

Включается всё через админку, без правки кода:

  1. Открыть Настройки → Настройки продукта → Композитный сайт.
  2. Выбрать режим работы — автокомпозит (система сама решает, что кешировать) или ручной (управляете вручную через API).
  3. Указать список доменных имён, для которых композит активен — если сайт мультидоменный, перечислить все.
  4. Задать маску включения, например *.html, чтобы композит не лез на служебные адреса.
  5. Сохранить настройки и очистить кеш — без этого старые страницы продолжат отдаваться из обычного кеша.

Файлы композитного кеша лежат в /bitrix/html_pages/. Если перед сайтом стоит Nginx, имеет смысл отдавать эти файлы напрямую, минуя PHP:

SHELL
# Структура композитного кеша
/bitrix/html_pages/<домен>/<путь>/index.html
# Пример: /bitrix/html_pages/example.ru/catalog/iphone/index.html

# Фрагмент конфигурации Nginx
set $composite_file /bitrix/html_pages/$http_host$request_uri/index.html;

if (-f $document_root$composite_file) {
    rewrite ^(.*)$ $composite_file last;
}

Для управления динамическими областями в технологии «Композитный сайт» используется класс Bitrix\Main\Page\Frame. Он позволяет помечать блоки страницы как «отложенные», сохраняя статический HTML в кеш и внедряя JS-код для их последующей загрузки через аякс. Ключевым элементом является заглушка — временный контент, отображаемый до получения данных. Начиная с версии main 14.5.2, содержимое заглушки учитывается в хеш-сумме кеша. Это обеспечило корректную инвалидацию страниц при изменении статики внутри динамических зон (например, кодов счетчиков), предотвращая отображение устаревших данных.

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

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

Кэширование компонентов и CPHPCache: что и как кешировать

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

Есть два уровня кеширования, и путать их нельзя. Первый — штатный кеш компонента: параметры CACHE_TYPE, CACHE_TIME, CACHE_GROUPS, которые передаются прямо в вызове $APPLICATION->IncludeComponent(). Битрикс сам решает, что кешировать, сам пишет в /bitrix/cache/ и сам сбрасывает при изменении данных инфоблока. Второй — ручное кеширование через CPhpCache: вы сами оборачиваете тяжёлую выборку в InitCache() и StartDataCache() и сами управляете тем, когда кеш инвалидируется. Первого хватает в 80% случаев: типовые компоненты bitrix:news.list, bitrix:catalog.section уже умеют кешироваться. Второй нужен, когда вы пишете свою выборку напрямую через CIBlockElement::GetList или агрегируете данные из нескольких инфоблоков, и штатный механизм компонента тут ни при чём.

Как включить кеш у штатного компонента: параметры CACHE_TYPE, CACHE_TIME, CACHE_GROUPS

У любого штатного компонента есть три ключевых параметра кеша. CACHE_TYPE принимает три значения: N (компонент не кэшируется никогда), A (автокеширование — компонент кэшируется, если в разделе «Настройки > Настройки продукта > Автокеширование» глобально включена соответствующая галочка) и Y (принудительное включение кеша). CACHE_TIME — время жизни кеша в секундах: 3600 для каталога, который меняется раз в час, 86400 для статичных справочников. CACHE_GROUPS — тонкий момент: если поставить Y, кеш будет отдельным для каждой группы пользователей, что критично, когда в шаблоне выводятся цены по группам или скрытые для гостя блоки. Если такой логики нет — ставьте N, иначе плодятся лишние копии кеша.

В наших проектах мы обычно держим CACHE_TYPE=A и CACHE_GROUPS=N для листингов каталога и Y — только там, где реально показываем разный контент разным группам. Главное правило: включённый кеш компонента сбрасывается автоматически при изменении элементов инфоблока — об этом позаботилось ядро.

PHP
<?php
$APPLICATION->IncludeComponent(
    'bitrix:news.list',
    'catalog_list',
    [
        'IBLOCK_ID'          => 12,          // замените на ваш IBLOCK_ID
        'NEWS_COUNT'         => 30,
        'SORT_BY1'           => 'SORT',
        'SORT_ORDER1'        => 'ASC',
        'CACHE_TYPE'         => 'A',         // автокеширование
        'CACHE_TIME'         => 3600,        // час
        'CACHE_GROUPS'       => 'N',         // кеш общий для всех групп
        'CACHE_FILTER'       => 'Y',         // учитывать фильтр в ключе кеша
    ],
    false
);

CACHE_GROUPS=N здесь означает, что один и тот же закешированный HTML отдаётся и гостю, и авторизованному — это безопасно, только если в шаблоне нет вывода, зависящего от пользователя.

Ручное кеширование через CPhpCache: InitCache и StartDataCache

Когда выборка идёт напрямую, компонент вам не помощник. Классический случай — блок «Топ-10 товаров раздела» или агрегат по нескольким инфоблокам: считать это на каждый хит дорого, а штатный кеш компонента не применим. Здесь на сцену выходит CPhpCache. Схема простая: вызываете InitCache(), проверяете результат, и если кеша нет — выполняете тяжёлую работу внутри StartDataCache() и закрываете её EndDataCache().

Ключевой момент — второй аргумент StartDataCache(): строка uniq_str. Это «отпечаток» или уникальный ID, от которого зависит кеш. Четвёртый аргумент (vars) служит для сохранения массива переменных в кеш-файл, чтобы они были доступны после его извлечения. Если не включить идентификаторы данных в uniq_str, кеш не будет уникальным. Для управления актуальностью кеша при изменении данных в инфоблоках обычно используют дополнительные механизмы очистки или теги.

PHP
<?php
use Bitrix\Main\Loader;
Loader::includeModule('iblock');

$sectionId = (int)($_REQUEST['SECTION_ID'] ?? 0);
$cacheId   = 'catalog_top_' . $sectionId;
$cache     = new CPHPCache();
$cacheTime = 3600;

if ($cache->InitCache($cacheTime, $cacheId, '/catalog_top/')) {
    $arResult = $cache->GetVars();
} else {
    $arCacheVars = [
        'IBLOCK_ID' => 12,          // замените на ваш IBLOCK_ID
        'SECTION_ID' => $sectionId,
    ];
    $cache->StartDataCache($cacheTime, $cacheId, '/catalog_top/', $arCacheVars);

    $arResult = [];
    $res = CIBlockElement::GetList(
        ['SORT' => 'ASC'],
        ['IBLOCK_ID' => 12, 'SECTION_ID' => $sectionId, 'ACTIVE' => 'Y'],
        false,
        ['nTopCount' => 10],
        ['ID', 'NAME', 'DETAIL_PAGE_URL', 'PROPERTY_PRICE']
    );
    while ($row = $res->Fetch()) {
        $arResult[] = $row;
    }

    $cache->EndDataCache($arResult);
}

// дальше $arResult используется в шаблоне

Этот код можно копировать в result_modifier.php компонента или в собственный обработчик — он самодостаточен.

Разберём сигнатуры, чтобы вы понимали, что именно крутить под свой проект. InitCache(int $TTL, string $uniq_str, mixed $initdir = false, string $basedir = 'cache') — первые два аргумента это время жизни и уникальная строка-идентификатор. $initdir задаёт подкаталог внутри /bitrix/cache/, куда лягут файлы; если оставить false, кеш уедет в общую свалку, и разбирать её будет больно. Мы всегда задаём осмысленный $initdir вроде '/catalog_top/' — так проще чистить точечно. $basedir по умолчанию 'cache', трогать его почти никогда не нужно.

Метод StartDataCache() принимает те же TTL и $uniq_str, а четвёртым аргументом — массив vars. Этот массив задаёт PHP-переменные, которые сохраняются в файле кеша и затем возвращаются методом GetVars(). Автоматическую инвалидацию кеша при изменении данных инфоблока обеспечивает не vars, а тегированный (управляемый) кеш: при правках элементов ядро сбрасывает кеши, привязанные к соответствующим тегам. Если вы ведёте данные не через инфоблок (например, тянете из внешнего API), автоматического сброса не будет — придётся вешать свой обработчик на событие обновления и вызывать $cache->Clean($uniq_str, $initdir) вручную.

Осторожно с CACHE_SELECTED_ITEMS. У компонента меню этот параметр влияет на привязку кеша к адресу страницы. При некорректной настройке это может привести к созданию множества копий кеша для разных разделов сайта. Проверьте вызов bitrix:menu: правильное использование параметра помогает избежать раздувания кеша и оптимизировать время отклика сервера.

Как ускорить Битрикс через настройки PHP и MySQL

Композит включён, компоненты кешируются, а страница каталога всё равно отдаётся медленно. Значит, кеш уже не при чём — упёрлись в сервер. На этом этапе в игру вступают параметры PHP и MySQL, и именно здесь часто прячется самый дешёвый прирост производительности: без переписывания шаблонов и без покупки нового железа.

Что реально влияет на скорость Битрикса со стороны окружения. Лимит памяти PHP — если он занижен, тяжёлые страницы с выборками падают или уходят в своп. Настройки mbstring — при неверной кодировке функции строк работают медленнее и иногда возвращают мусор. Со стороны MySQL — performance_schema, который на слабых машинах только жрёт память, и thread_pool_size, влияющий на обработку параллельных запросов. Отдельная тема — размещение временных файлов в RAM-диск: MySQL активно пишет tmp-таблицы, и перенос tmpdir в память убирает лишний I/O.

На BitrixVM часть этих параметров уже настроена автоматически через сервис bvat: он подбирает значения Apache, PHP, MySQL и nginx под ресурсы сервера. Но под конкретную нагрузку — большой каталог, активный импорт — дефолтов не всегда хватает, и часть параметров приходится править руками. Ниже — что именно и где менять.

Параметр Где задаётся Рекомендуемое значение Зачем
memory_limit php.ini / z_bx_custom.ini 256M (для дефолтных конфигураций) Тяжёлые выборки и импорт не уходят в своп
php.ini 2 Корректная и быстрая работа строковых функций в UTF-8
mbstring.internal_encoding php.ini UTF-8 Кодировка по умолчанию для mbstring
performance_schema [mysqld] в my.cnf OFF на слабых серверах Освобождает память на машинах с малым объёмом RAM
thread_pool_size [mysqld] 16 (дефолт MySQL 8) Число параллельных потоков обработки запросов
tmpdir [mysqld] путь в RAM-диск Временные таблицы пишутся в память, а не на диск

Пользовательские конфиги складываем в отдельные файлы, которые не перезаписываются BitrixEnv — иначе bvat или обновление затрёт правки:

SHELL
# PHP: /etc/php.d/z_bx_custom.ini
memory_limit = 256M
mbstring.func_overload = 0
default_charset = UTF-8

# MySQL: /etc/mysql/conf.d/z_bx_custom.cnf
[mysqld]
performance_schema = OFF
thread_pool_size = 16
tmpdir = /dev/shm/mysql-tmp

Почему нельзя править файлы прямо в /bitrix/modules и дефолтные конфиги BitrixVM — их перезапишет либо обновление продукта, либо тот же bvat при очередной реконфигурации. Всё, что мы меняем руками, должно жить в отдельных файлах, которые никто не трогает. Это правило действует и для PHP, и для MySQL: /etc/php.d/z_bx_custom.ini и /etc/mysql/conf.d/z_bx_custom.cnf подключаются после дефолтных и не перезаписываются.

Проверить, что настройки применились, просто. Для PHP — php -i | grep memory_limit и аналогично по mbstring-параметрам. Для MySQL — SHOW VARIABLES LIKE 'performance_schema'; и SHOW VARIABLES LIKE 'thread_pool_size'; прямо в консоли. Если значения не совпадают с ожидаемыми, значит конфиг не подхватился: проверьте путь, права и порядок подключения в my.cnf.

Перенос tmpdir в RAM-диск имеет смысл, когда MySQL активно строит временные таблицы — например, при сортировках в большом каталоге или при импорте. На сервере с запасом памяти это даёт заметный выигрыш, но при дефиците RAM лучше сначала разобраться с лимитами, а не отдавать память под tmp.

Осторожно на слабых серверах. На машинах с 512 МБ RAM стандартные настройки MySQL в BitrixVM могут привести к дефициту памяти и падению сервера под нагрузкой. При оптимизации конфигурации в секции [mysqld] важно учитывать лимиты ресурсов и отключать лишние опции для экономии ОЗУ. Проверяйте фактическое потребление памяти после каждого изменения, а не только по документации.

Redis и Memcache в Битрикс: когда они реально помогают

Типичный сценарий: композит включён, компоненты кешируются, PHP и MySQL подкручены, а MySQL всё равно упирается в потолок по количеству одновременных соединений. Причина в том, что кеш по умолчанию живёт в файлах, а сессии — в базе. Каждый анонимный посетитель, каждый авторизованный пользователь, каждый запрос к CPHPCache — всё это уходит в MySQL или на диск, который под нагрузкой становится узким местом не хуже самой базы.

В ядре Bitrix Framework есть штатные подключения к Redis и Memcache — они выносят кеш и сессии из MySQL в оперативную память. Это не «серебряная пуля», а конкретный инструмент под конкретную нагрузку. Тратить время на настройку имеет смысл, когда выполнено хотя бы одно условие: каталог от 20 000 SKU, стабильная посещаемость выше нескольких тысяч визитов в сутки, много авторизованных пользователей (личный кабинет, B2B-портал, история заказов). Если у вас витрина на 2 000 товаров и пара сотен визитов — Redis не даст заметного выигрыша, а лишний демон на сервере добавит точку отказа.

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

PHP
<?php
// bitrix/.settings.php
return [
    'cache' => [
        'value' => [
            'type' => [
                'class_name' => '\Bitrix\Main\Data\CacheEngineRedis',
                'extension' => 'redis',
            ],
            'redis' => [
                'host' => '127.0.0.1',
                'port' => 6379,
                'timeout' => 2.0,
            ],
            'sid' => 'bitrix-cache',
        ],
    ],
    'session' => [
        'value' => [
            'mode' => 'default',
            'handlers' => [
                'general' => [
                    'type' => 'redis',
                    'host' => '127.0.0.1',
                    'port' => 6379,
                ],
            ],
        ],
    ],
];

В Redis уходит три категории данных: кеш компонентов и managed cache (то, что раньше писалось в /bitrix/cache/), сессии и мелкие служебные выборки. В MySQL при этом остаётся всё, что касается транзакционных данных: заказы, корзины, остатки, свойства товаров. Их кешировать в Redis нельзя — данные должны быть консистентны, а Redis для этого не предназначен. Именно поэтому Redis не отменяет нормальный кеш на уровне компонентов: он лишь меняет место хранения, а не логику.

Проверить эффект проще всего через панель производительности (Настройки > Производительность > Панель производительности): замеряем до подключения Redis и после, сравниваем число запросов к MySQL и общее время генерации страницы. Если разница в пределах погрешности — Redis вам не нужен, откатите настройку.

Что касается выбора между Memcache и Redis: Memcache проще — это чистый key-value для кеша без персистентности. Redis гибче: поддерживает разные типы данных, репликацию и сохранение на диск. В Bitrix Framework Redis доступен как один из штатных вариантов для хранения сессий наряду с файлами и Memcache. Если у вас уже настроен memcached под кеш — не обязательно мигрировать. Но новые проекты мы обычно поднимаем на Redis.

Панель производительности Битрикс: как замерить результат

Многие думают, что оптимизация — это про «включить композит и Redis», но без замера любая правка — это вера, а не инженерия. Мы регулярно видим проекты, где админ неделю правит настройки PHP, а потом выясняется, что узкое место было в одном некешируемом компоненте. Чтобы такого не было, в Bitrix есть встроенный инструмент — Панель производительности. Она находится по пути Настройки > Производительность > Панель производительности и умеет тестировать конкретную страницу: прогоняет её через сценарий нагрузки и сравнивает результат с эталонной системой.

Эталон — это не ваш сервер и не ваш проект. Это усреднённые показатели «здоровой» конфигурации Bitrix на типовом железе, которые 1С-Битрикс закладывает как ориентир. Сравнивать с ним полезно, потому что абсолютные цифры в отрыве от контекста ничего не значат: страница может генерироваться 0.8 секунды на мощном выделенном сервере и 3 секунды на VPS — и обе цифры «нормальны» для своей среды. А вот расхождение с эталоном по числу запросов и по времени генерации показывает, где именно вы отстаёте от типовой картины. Об этом мы подробнее скажем ниже.

Пошаговый сценарий, которым пользуемся мы сами:

  1. Открыть Настройки > Производительность > Панель производительности и убедиться, что модуль «Производительность» установлен.
  2. Запустить тест на типовой странице каталога — не на главной и не на карточке товара, а именно на листинге раздела, потому что там основной вес выборки и пагинации.
  3. Зафиксировать три ключевых числа: время генерации страницы, количество SQL-запросов, объём потреблённой памяти.
  4. Внести одну правку — например, включить кеш конкретного компонента или поменять маску композита.
  5. Повторить тест на той же странице и сравнить с предыдущим замером.

Почему сравнивать с эталоном важнее абсолютных цифр? Потому что эталон показывает структуру нагрузки, а не скорость железа. Если у вас 400 запросов на страницу каталога против эталонных 80 — это сигнал, что где-то не работает кеш выборок или отключён управляемый кеш ORM. Если запросов столько же, а время генерации втрое выше — проблема, скорее всего, в самих запросах: тяжёлые JOIN'ы, отсутствие индексов, выборка всех свойств разом. Это уже другой класс задач, и лечится он не настройками, а профилированием SQL.

Отдельный сюжет — когда после включения композита цифры не улучшились. Часто страница просто не попадает под условия работы технологии или маски включения, заданные в системе. Проверьте конфигурацию в Настройки > Настройки продукта > Композитный сайт и убедитесь, что тестовый URL, включая все параметры запроса, соответствует правилам и не исключен из процесса кеширования.

Самые частые ошибки при оптимизации Битрикс

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

Ниже шесть ошибок, которые мы встречаем чаще всего. По каждой: в чём суть, почему так делать нельзя и что делать вместо. Часть напрямую вытекает из предыдущих секций — композита, кеширования, PHP-настроек, — но здесь мы собрали их в один чек-лист, чтобы было проще пройтись по своему проекту.

Ошибка Причина Решение
Композит включён без выноса динамики Динамические блоки (корзина, авторизация, счётчики) попадают в статический HTML и кешируются для всех Обернуть динамику в Frame или вынести в отдельные ajax-компоненты до включения композита
CACHE_SELECTED_ITEMS=Y на фильтрах Кеш привязывается к адресу страницы — на каждый URL свой вариант, кеш не переиспользуется Для страниц с фильтрами ставить N и кешировать выборку отдельно по параметрам фильтра
Правка ядра вместо /local Файлы в /bitrix/modules перезаписываются при обновлении — правки исчезают Свой модуль или обработчики событий в /local/php_interface
performance_schema на слабом сервере Сборщик статистики MySQL съедает память и CPU, которых и так мало Для машин с 512 МБ RAM — performance_schema = off в [mysqld]
Redis подключён без предварительного кеша Redis ускоряет доступ к данным, но не создаёт их — при промахе всё равно идёт запрос в БД Сначала настроить кеш компонентов и CPHPCache, потом подключать Redis
Отключение mbstring.func_overload Ломает работу строковых функций ядра и кодировку UTF-8 на сайте Оставить mbstring.func_overload=2 и mbstring.internal_encoding=UTF-8

Отдельно остановимся на двух пунктах, которые чаще всего приводят к необратимым последствиям — правке ядра и настройке mbstring.

Правки в /bitrix/modules — это классика. Разработчик открывает модуль, добавляет пару строк в компонент, всё работает. При ближайшем обновлении ядра эти строки исчезнут: Bitrix перезапишет файлы модуля, и никто не вспомнит, что там было. Вместо правки ядра есть два пути. Собственный модуль, если логика нетривиальная и переиспользуется. Или обработчики в /local/php_interface/init.php, если нужно перехватить событие и подменить данные. Второй вариант быстрее и подходит для 80% задач. Если нужна подмена шаблона компонента — копируем его в /local/templates/, а не правим исходник.

С mbstring.func_overload история коварнее. В старых гайдах встречается совет «отключить, чтобы не было конфликтов». И это ломает UTF-8 на сайте: strlen, substr и другие функции начинают считать байты вместо символов, кириллица при обрезке превращается в кракозябры. Для Bitrix корректная настройка — mbstring.func_overload=2 и mbstring.internal_encoding=UTF-8. Проверять это нужно после каждого обновления PHP, потому что дефолты в дистрибутивах меняются.

Перед каждым релизом у нас в чек-листе три пункта: диф по /bitrix/modules (не появилось ли правок ядра), актуальность mbstring и отсутствие хардкода доступов в конфигах и шаблонах. Первые два ловят технический долг, третий — потенциальную утечку.

Подробнее об услуге: поддержка и сопровождение сайтов на Битрикс.

Частые вопросы

Можно ли включить композит на страницах с авторизованными пользователями?

Да, но только в режиме динамического композита: в настройках модуля «Композитный сайт» включите опцию «Динамический композит» и оберните персональные блоки в компонент bitrix:main.include с параметром DYNAMIC или используйте $APPLICATION->ShowProperty. Статический композит для авторизованных отдаёт закешированную страницу и покажет чужие данные.

Чем отличается CPHPCache от managed cache (Bitrix\Main\Data\Cache) и что выбрать?

CPHPCache — старый API с ручным управлением через InitCache/StartDataCache/EndDataCache и обязательным указанием TTL и baseDir. Managed cache ($cache = Bitrix\Main\Data\Cache::createInstance()) сам инвалидируется по тегам и работает поверх того же механизма, поэтому для нового кода берите managed cache, а CPHPCache оставляйте в легаси-компонентах.

Что делать, если после включения Redis сайт стал работать медленнее?

Проверьте, что в .settings.php для секции 'cache' указан 'type' => 'redis' с корректными 'host' и 'port', а не оставлен файловый кэш при подключённом расширении. Также уберите кэширование сессий в Redis (параметр 'session' в 'redis' => ['session' => false]), если сессии пишутся часто — на них Redis часто становится узким местом.

А если у меня shared-хостинг без root — что реально можно ускорить?

Включите композит, OPcache (через .user.ini: opcache.enable=1, opcache.memory_consumption=128), HTML-кэш и кэш компонентов с большим TTL, а также переведите кэш на Memcached, если провайдер даёт сокет. Настройки MySQL и php-fpm без root недоступны — их меняет только хостер по тикету.

Как в панели производительности отличить проблему в PHP от проблемы в MySQL?

На вкладке «Время выполнения» смотрите колонку «Время» по компонентам и «Запросы» — если суммарное время SQL-запросов превышает 50% от общего, узкое место в БД (индексы, JOIN, кэш запросов). Если время уходит в компоненты при малом числе запросов — проблема в PHP-коде и отсутствии кэша.

Можно ли кэшировать результат компонента, который зависит от $_GET, не плодя сотни кэш-файлов?

Да, передайте в $arParams['CACHE_GROUPS'] => 'N' и сформируйте $cacheId только из значимых параметров, например md5(serialize([$arParams['IBLOCK_ID'], $_GET['SECTION']])). Не включайте в $cacheId весь $_GET — иначе получите отдельный кэш на каждый UTM-метку.

#Bitrix #PHP #MySQL #Nginx #SEO
автор · Backend / SRE Engineer
Артем Колячек

Backend-разработчик и SRE в студии Paradigma. Занимается тем, что у других проектов обычно обнаруживается за неделю до запуска: переездом Bitrix-проектов между серверами, починкой кешей после миграций, выстраиванием pipeline для контейнеров, мониторингом под нагрузкой.

До Paradigma — 7 лет в backend (PHP + Postgres) и в operations (Linux, Docker, Coolify, restic-бэкапы). Любит когда логи разговаривают полным синтаксисом ошибки, а не «что-то пошло не так».

На блоге пишет ровно про те ситуации с которыми сам разбирался руками: какой Bitrix-апдейт сломал кеш и как откатить, почему Docker-сеть не находит контейнер после рекрейта, что делать когда asyncpg ругается на event loop.