Стрес-тестування обміну 1С і 1С-Бітрікс
Обмін працює на невеликій базі, але ламається при реальних обсягах даних. Це типова картина: тестували на 1 000 товарів — все гаразд, на 50 000 — таймаут PHP, переповнення пам'яті, deadlocks у базі. Стрес-тестування обміну — це навантаження даними, близькими до виробничих, із фіксацією вузьких місць і граничних показників до запуску в продакшн.
Архітектура обміну та точки навантаження
Стандартний обмін через CommerceML працює поетапно:
1С → Експорт XML (catalog.xml, offers.xml, import.xml)
↓
Бітрікс → POST /bitrix/admin/1c_exchange.php
↓
Розбір XML (SimpleXML / XMLReader)
↓
Запис до b_iblock_element, b_iblock_element_property, b_catalog_price
Вузькі місця при обсязі 50 000+ SKU:
-
Розбір XML —
SimpleXMLзавантажує весь файл у пам'ять. При файлі 200 МБ зmemory_limit = 256M— out of memory. Рішення:XMLReaderдля потокового читання. -
Запис у базу — стандартний
CIBlockElement::Add()/CIBlockElement::Update()працює порядково. 50 000 елементів × 50 мс = 40 хвилин лише на запис. - Перерахунок цін — після кожного оновлення ціни перераховуються накопичувальні знижки. При пакетному записі це потрібно відкласти на кінець імпорту.
Методологія стрес-тесту
Підготовка тестових даних. Генеруємо XML-файл обміну з реалістичним обсягом: стільки товарів, SKU та цін, скільки буде в продакшні, плюс 30% запас.
Генератор тестових даних для CommerceML:
class CatalogXmlGenerator
{
public function generate(int $productCount, string $outputPath): void
{
$writer = new \XMLWriter();
$writer->openUri($outputPath);
$writer->startDocument('1.0', 'UTF-8');
$writer->startElement('КоммерческаяИнформація');
for ($i = 1; $i <= $productCount; $i++) {
$this->writeProduct($writer, $i);
}
$writer->endElement();
$writer->endDocument();
$writer->flush();
}
private function writeProduct(\XMLWriter $w, int $i): void
{
$w->startElement('Товар');
$w->writeElement('Ід', "product-uuid-{$i}");
$w->writeElement('Найменування', "Тестовий товар #{$i}");
$w->writeElement('Артикул', "ART-{$i}");
// ... властивості, ціни
$w->endElement();
}
}
Параметри вимірювання:
| Метрика | Інструмент | Норматив |
|---|---|---|
| Час повного імпорту | Секундомір + логи | < 60 хв для 50 000 SKU |
| Пік споживання пам'яті PHP | memory_get_peak_usage() |
< 80% від memory_limit |
| Кількість SQL-запитів | SHOW STATUS LIKE 'Questions' |
< 10 запитів на елемент |
| Deadlocks у БД | SHOW ENGINE INNODB STATUS |
0 |
| CPU-навантаження сервера | top, Zabbix |
< 85% на піку |
Типові знахідки при стрес-тесті
Out of memory при розборі великого XML. Фікс: заміна simplexml_load_file() на XMLReader з потоковою обробкою:
$reader = new \XMLReader();
$reader->open($filePath);
while ($reader->read()) {
if ($reader->nodeType === \XMLReader::ELEMENT && $reader->localName === 'Товар') {
$node = new \SimpleXMLElement($reader->readOuterXml());
$this->processProduct($node);
unset($node); // звільняємо пам'ять
}
}
Deadlocks при паралельному обміні. Якщо запущений cron-обмін і водночас прийшов новий запит із 1С — обидва пишуть у b_iblock_element_property. Фікс: lock-файл або запис стану в b_option:
if (file_exists($lockFile)) {
throw new \RuntimeException('Import already running');
}
file_put_contents($lockFile, getmypid());
Повільний перерахунок знижок. Після масового запису цін викликається CCatalogDiscount::CountDiscount() для кожного елемента. При 50 000 SKU — критичне навантаження. Фікс: вимкнути автоперерахунок через подію OnBeforeCatalogDiscountCounters на час імпорту, запустити перерахунок одним викликом після завершення.
Тест продуктивності окремих операцій
| Операція | 1 000 SKU | 10 000 SKU | 50 000 SKU |
|---|---|---|---|
| Парсинг XML (SimpleXML) | 2 с | 20 с | Out of memory |
| Парсинг XML (XMLReader) | 1 с | 8 с | 38 с |
| Запис через CIBlockElement | 50 с | 8 хв | 40 хв |
| Запис через ORM batch | 8 с | 80 с | 7 хв |
| Оновлення лише цін | 3 с | 25 с | 2 хв |
Кейс: оптовий постачальник, 120 000 SKU
Проблема: обмін із 1С тривав 6 годин і завершувався з помилкою на 70% обсягу через перевищення max_execution_time.
Що зробили:
- Замінили
SimpleXMLнаXMLReader— розбір XML з 40 хв до 8 хв - Реалізували пакетний INSERT для властивостей (500 записів за транзакцію) — запис із 3 годин до 35 хв
- Відклали перерахунок знижок на після імпорту — заощадили ще 40 хв
- Розбили імпорт на чанки по 5 000 елементів із checkpoint'ами — виключили втрату прогресу при помилці
Підсумок: повний обмін 120 000 SKU за 47 хвилин, стабільно працює 8 місяців.
Що входить до стрес-тестування обміну
- Генерація тестових XML-файлів із реалістичним обсягом даних
- Вимірювання базових показників: час, пам'ять, SQL-запити, CPU
- Профілювання вузьких місць із рекомендаціями щодо оптимізації
- Виправлення виявлених проблем: XMLReader, пакетний запис, lock-механізм
- Повторний тест після оптимізації з підтвердженням результату
- Документація з граничних показників і рекомендованих налаштувань сервера







