Оптимизация Elasticsearch-индексов для 1С-Битрикс
Оптимизация индексов Elasticsearch под каталог и поиск Битрикс
Elasticsearch работает «из коробки» — до первой серьёзной нагрузки. На каталоге в 100 000+ товаров с активной переиндексацией через синхронизацию с 1С типичные симптомы деградации: heap memory постоянно под 80%, GC паузы по 200–500 мс, search latency растёт до 2–5 секунд, merge throttling блокирует индексацию.
Оптимизация индексов ES — это работа с несколькими уровнями: настройки шардирования, merge policy, fielddata и doc values, refresh interval, force merge для завершённых индексов.
Диагностика состояния кластера и индексов
Начинаем с оценки здоровья:
# Состояние кластера
GET /_cluster/health?pretty
# Статистика индексов
GET /bitrix_catalog/_stats?pretty
# Горячие потоки (что грузит CPU)
GET /_nodes/hot_threads
# Использование памяти
GET /_nodes/stats/jvm?pretty
Ключевые метрики для диагностики:
-
jvm.mem.heap_used_percent— если стабильно >75%, нужно либо увеличить heap, либо уменьшить fielddata -
indices.segments.count— большое число сегментов замедляет поиск; признак неоптимального merge -
indices.merges.current_size_in_bytes— активный merge в продакшне во время пиковой нагрузки
Настройка шардирования
Самая распространённая ошибка — слишком много шардов. Каждый шард — это Lucene-индекс с overhead по памяти около 50 МБ на heap. 100 шардов = 5 ГБ heap только на метаданные.
Для каталога Битрикс правило: 1 шард на каждые 20–40 ГБ данных, не более 3–5 шардов для типичного магазина:
PUT /bitrix_catalog
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}
Изменить число primary shards после создания индекса нельзя — нужно создать новый индекс и реиндексировать через Reindex API. Планируем правильно с первого раза.
Оптимизация refresh interval
По умолчанию ES обновляет индекс каждую секунду — новые документы становятся доступны для поиска через 1 с. Это дорого при массовой индексации:
PUT /bitrix_catalog/_settings
{
"index": {
"refresh_interval": "30s"
}
}
Во время синхронизации с 1С (bulk indexing) вообще отключаем refresh:
{ "index": { "refresh_interval": "-1" } }
После завершения — восстанавливаем и вызываем POST /bitrix_catalog/_refresh вручную.
Оптимизация merge policy
PUT /bitrix_catalog/_settings
{
"index.merge.policy.max_merged_segment": "5gb",
"index.merge.policy.segments_per_tier": 10,
"index.merge.scheduler.max_thread_count": 1
}
max_thread_count: 1 для HDD-серверов — merge на нескольких потоках убивает I/O. На NVMe можно ставить 2–4.
Оптимизация fielddata и doc values
Fielddata грузится в heap при агрегациях и сортировке по text-полям. Для фасетных фильтров каталога используем исключительно keyword с doc values (хранятся на диске, не в heap):
PUT /bitrix_catalog/_mapping
{
"properties": {
"brand": {
"type": "keyword",
"doc_values": true,
"eager_global_ordinals": true
}
}
}
eager_global_ordinals: true для высококардинальных полей фильтра (бренд, категория) — строит ordinals при refresh, а не при первом запросе агрегации. Устраняет «холодный старт» после ночной переиндексации.
Force merge для статичных индексов
Если каталог меняется по ночам (синхронизация с 1С раз в сутки), дневной индекс можно смержить в один сегмент:
POST /bitrix_catalog/_forcemerge?max_num_segments=1
Операция тяжёлая, запускаем только в техническое окно. Один сегмент = максимальная скорость поиска, минимальный overhead.
Настройка индексирования из Битрикс
На стороне PHP при пакетной индексации используем Bulk API с оптимальным размером пачки:
$batchSize = 500; // оптимум для товаров с описанием
$body = [];
foreach ($products as $product) {
$body[] = ['index' => ['_index' => 'bitrix_catalog', '_id' => $product['ID']]];
$body[] = $this->prepareDocument($product);
}
$client->bulk(['body' => $body]);
Размер пачки подбираем экспериментально: слишком маленький — много round-trips, слишком большой — GC pressure. Обычно 200–500 документов для товаров с описаниями.
Мониторинг после оптимизации
Подключаем метрики ES в Prometheus через elasticsearch_exporter и алертируем на:
- heap_used_percent > 80% в течение 5+ минут
- GC time > 1 секунда за 1 минуту
- search latency p99 > 500 мс
- unassigned shards > 0
Результат
Комплексная оптимизация индексов снижает heap utilization на 30–50%, убирает GC паузы при нормальной нагрузке, сокращает время поискового запроса с 1–3 с до 50–150 мс, ускоряет ночную переиндексацию каталога в 3–5 раз.







