Стресс-тестирование обмена 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 МБ на PHP с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-механизм
- Повторный тест после оптимизации с подтверждением результата
- Документация по предельным показателям и рекомендуемым настройкам сервера







