Обмін працює на невеликій базі, але ламається при реальних обсягах даних. Ми стикалися з цим не раз: тест на 1 000 товарів проходить за хвилину, а на 50 000 — таймаут PHP, переповнення пам'яті, deadlocks в базі. Типові симптоми: сайт падає, 1С видає помилку імпорту, потрібне відновлення з бекапу. Кожен збій обміну в годину пік може коштувати до $1.8k–2.6kів втраченої виручки. Стрес-тестування обміну — це навантаження даними, наближеними до виробничих, з фіксацією вузьких місць та граничних показників до запуску в продакшн. Наш досвід: команда має 10+ років досвіду в розробці на Бітрікс та провела понад 50 стрес-тестів для каталогів від 10 000 до 500 000 SKU. При такому підході виявлення проблем на етапі тестування економить до 40% бюджету на термінові доопрацювання. Отримайте консультацію щодо вашого обміну — ми оцінимо сценарій за один день.
Архітектура обміну та точки навантаження
Стандартний обмін через 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 МБ на PHP зmemory_limit = 256M— out of memory. Рішення: XMLReader для потокового читання. - Запис у базу — стандартний
CIBlockElement::Add()/CIBlockElement::Update()працює порядно. 50 000 елементів × 50 мс = 40 хвилин тільки на запис. - Перерахунок цін — після кожного оновлення ціни перераховуються накопичувальні знижки. При пакетному записі це потрібно відкласти на кінець імпорту.
Чому обмін ламається на великих обсягах?
Основні причини — архітектурні обмеження стандартних компонентів. SimpleXML створює дерево об'єктів у пам'яті, що для файлу 200 МБ дає >1 ГБ споживання. Плюс CIBlockElement::Add() виконує безліч окремих SQL-запитів (перевірка прав, події, кешування). На 50 000 елементах кількість запитів перевалює за 500 000, що викликає таймаути БД.
Як ми виявляємо вузькі місця?
Генератор тестових даних для 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(); } } Підготовка тестових даних
Генеруємо XML-файл обміну з реалістичним обсягом: стільки товарів, SKU та цін, скільки буде в продакшні плюс 30% запас.
Параметри заміру
| Метрика | Інструмент | Норматив |
|---|---|---|
| Час повного імпорту | Секундомір + логи | < 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); // звільняємо пам'ять } } Рекомендація з документації PHP
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 хв |
XMLReader у 5 разів ефективніший за SimpleXML для великих файлів — це видно за часом парсингу 10 000 SKU.
Кейс: оптовий постачальник, 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 хвилин, працює стабільно більше півроку. Економія часу — 80%.
Що входить у стрес-тестування обміну
- Генерація тестових XML-файлів з реалістичним обсягом даних
- Замір базових показників: час, пам'ять, SQL-запити, CPU
- Профілювання вузьких місць з рекомендаціями щодо оптимізації
- Виправлення виявлених проблем: XMLReader, пакетний запис, lock-механізм
- Повторний тест після оптимізації з підтвердженням результату
- Документація щодо граничних показників та рекомендованих налаштувань сервера
Своєчасне виявлення проблем економить від $900–1.3kів на екстрених виправленнях. Гарантуємо, що після нашого доопрацювання обмін витримає заявлене навантаження. Замовте стрес-тест та отримайте детальний протокол. Працюємо за договором з фіксацією метрик у протоколі.







