Оптимізація переіндексації Elasticsearch для 1С-Бітрікс
Оптимізація переіндексації Elasticsearch для 1С-Бітрікс
На проекті з 800 000 SKU планова переіндексація з 1С займала 14 годин. За цей час накопичувалася черга змін, пошук віддавав застарілі дані, а імпорт з 1С конкурував з переіндексацією за ресурси. Завдання — скоротити повну переіндексацію до 1–2 годин без зупинки пошуку.
Чому переіндексація гальмує
Типові причини повільної переіндексації:
Послідовна індексація через одиночні запити. Кожен документ надсилається окремим PUT /bitrix_catalog/_doc/{id}. HTTP-накладні витрати, TCP-з'єднання на кожен запит, відповідь 200ms * 800000 = 160000 секунд.
Занадто маленький batch у Bulk API. Розмір пакета 10 документів замість оптимальних 200–1000.
Refresh після кожного пакета. Примусовий POST /bitrix_catalog/_refresh після кожного batch — самогубство продуктивності. Refresh створює новий сегмент Lucene, блокує індексацію на десятки мілісекунд.
Неправильний refresh_interval під час переіндексації. Дефолтні 1 секунда генерують сотні тисяч дрібних сегментів, які ES витрачає сили на merge.
Стратегія zero-downtime переіндексації
Ключовий прийом — індексувати в новий індекс, а не поверх робочого:
Поточний: bitrix_catalog_v1 <-- аліас bitrix_catalog
Новий: bitrix_catalog_v2 <-- індексуємо сюди
Після: перемикаємо аліас на v2
// Створюємо аліас при початковому налаштуванні
POST /_aliases
{
"actions": [
{ "add": { "index": "bitrix_catalog_v1", "alias": "bitrix_catalog" } }
]
}
Бітрікс працює з аліасом bitrix_catalog. Поки йде переіндексація в v2, пошук продовжує працювати через v1. Після завершення атомарно перемикаємо аліас.
Налаштування Elasticsearch для швидкої індексації
Перед переіндексацією тимчасово змінюємо налаштування через API:
PUT /bitrix_catalog_v2/_settings
{
"index": {
"refresh_interval": "-1",
"number_of_replicas": 0,
"translog.durability": "async",
"translog.sync_interval": "30s"
}
}
refresh_interval: -1 повністю вимикає автоматичний refresh — документи не потрапляють в пошук до явного refresh, зате індексація прискорюється в 3–5 разів.
number_of_replicas: 0 вимикає реплікацію на час індексації. ES не витрачає час на копіювання шардів.
translog.durability: async — транслог скидається на диск не при кожній операції, а за таймером. Ризик втрати даних при збої за останні 30 секунд — прийнятно для переіндексації, не для продакшн-даних.
Після завершення відновлюємо налаштування:
PUT /bitrix_catalog_v2/_settings
{
"index": {
"refresh_interval": "5s",
"number_of_replicas": 1,
"translog.durability": "request"
}
}
Потім примусовий merge для зменшення кількості сегментів:
POST /bitrix_catalog_v2/_forcemerge?max_num_segments=1
Оптимізація PHP-індексатора
Розмір пакета для Bulk API підбираємо емпірично. Орієнтир — 5–15 МБ на один запит:
$batchSize = 500; // документів на один bulk-запит
$bulk = [];
foreach ($products as $product) {
$bulk[] = ['index' => ['_index' => 'bitrix_catalog_v2', '_id' => $product['ID']]];
$bulk[] = buildDocument($product);
if (count($bulk) >= $batchSize * 2) {
$client->bulk(['body' => $bulk]);
$bulk = [];
// НЕ викликаємо _refresh тут
}
}
if (!empty($bulk)) {
$client->bulk(['body' => $bulk]);
}
Паралельна індексація через кілька процесів — ділимо каталог за діапазонами ID:
# Процес 1: ID 1 - 200000
php index_products.php --from=1 --to=200000 &
# Процес 2: ID 200001 - 400000
php index_products.php --from=200001 --to=400000 &
# Процес 3: ID 400001 - 600000
php index_products.php --from=400001 --to=600000 &
wait
echo "Indexing complete"
Три паралельних процеси на 3-нодовому кластері дають лінійне прискорення. Обмеження — пропускна здатність MySQL при читанні даних.
Перемикання аліасу
Після завершення індексації атомарно перемикаємо аліас:
POST /_aliases
{
"actions": [
{ "remove": { "index": "bitrix_catalog_v1", "alias": "bitrix_catalog" } },
{ "add": { "index": "bitrix_catalog_v2", "alias": "bitrix_catalog" } }
]
}
Операція атомарна — між видаленням старого аліасу і додаванням нового немає моменту, коли аліас не існує. Перемикання займає мілісекунди, пошук не переривається.
Результат
На каталозі 800к SKU після оптимізації: повна переіндексація 1 год 20 хв (було 14 год), інкрементальне оновлення 200–300 документів на секунду через Bulk API замість 15–20 через одиночні запити.







