Stress Testing of 1C and 1C-Bitrix Data Exchange
The exchange works fine on a small dataset, but breaks under real data volumes. This is a typical scenario: tested on 1,000 products — everything is fine; on 50,000 — PHP timeout, memory overflow, database deadlocks. Stress testing the exchange means applying production-scale data load, identifying bottlenecks, and measuring limits before going live.
Exchange Architecture and Load Points
The standard exchange via CommerceML operates in stages:
1C → XML Export (catalog.xml, offers.xml, import.xml)
↓
Bitrix → POST /bitrix/admin/1c_exchange.php
↓
XML parsing (SimpleXML / XMLReader)
↓
Write to b_iblock_element, b_iblock_element_property, b_catalog_price
Bottlenecks at 50,000+ SKU:
-
XML parsing —
SimpleXMLloads the entire file into memory. A 200 MB file withmemory_limit = 256M— out of memory. Solution:XMLReaderfor streaming. -
Database writes — the standard
CIBlockElement::Add()/CIBlockElement::Update()operates row by row. 50,000 elements × 50 ms = 40 minutes for writes alone. - Price recalculation — after every price update, cumulative discounts are recalculated. During batch writes, this should be deferred to the end of the import.
Stress Test Methodology
Preparing test data. Generate an exchange XML file with a realistic volume: as many products, SKUs, and prices as production will have, plus a 30% buffer.
Test data generator for 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('Наименование', "Test product #{$i}");
$w->writeElement('Артикул', "ART-{$i}");
// ... properties, prices
$w->endElement();
}
}
Measurement parameters:
| Metric | Tool | Benchmark |
|---|---|---|
| Total import time | Timer + logs | < 60 min for 50,000 SKU |
| Peak PHP memory usage | memory_get_peak_usage() |
< 80% of memory_limit |
| Number of SQL queries | SHOW STATUS LIKE 'Questions' |
< 10 queries per element |
| Database deadlocks | SHOW ENGINE INNODB STATUS |
0 |
| Server CPU load | top, Zabbix |
< 85% at peak |
Typical Stress Test Findings
Out of memory when parsing large XML. Fix: replace simplexml_load_file() with XMLReader for streaming:
$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); // free memory
}
}
Deadlocks during concurrent exchange. If a cron-based exchange is running and a new request arrives from 1C simultaneously — both write to b_iblock_element_property. Fix: lock file or write state to b_option:
if (file_exists($lockFile)) {
throw new \RuntimeException('Import already running');
}
file_put_contents($lockFile, getmypid());
Slow discount recalculation. After bulk price writes, CCatalogDiscount::CountDiscount() is called for each element. At 50,000 SKU — critical load. Fix: disable auto-recalculation via the OnBeforeCatalogDiscountCounters event during import, then trigger recalculation once after completion.
Performance Test for Individual Operations
| Operation | 1,000 SKU | 10,000 SKU | 50,000 SKU |
|---|---|---|---|
| XML parsing (SimpleXML) | 2 s | 20 s | Out of memory |
| XML parsing (XMLReader) | 1 s | 8 s | 38 s |
| Write via CIBlockElement | 50 s | 8 min | 40 min |
| Write via ORM batch | 8 s | 80 s | 7 min |
| Price-only update | 3 s | 25 s | 2 min |
Case Study: Wholesale Supplier, 120,000 SKU
Problem: 1C exchange took 6 hours and failed at 70% completion due to max_execution_time being exceeded.
What was done:
- Replaced
SimpleXMLwithXMLReader— XML parsing reduced from 40 min to 8 min - Implemented batch INSERT for properties (500 records per transaction) — writes reduced from 3 hours to 35 min
- Deferred discount recalculation to after the import — saved another 40 min
- Split import into chunks of 5,000 elements with checkpoints — eliminated progress loss on error
Result: full exchange of 120,000 SKU in 47 minutes, running stably for 8 months.
What Is Included in Exchange Stress Testing
- Generation of test XML files with realistic data volumes
- Measurement of baseline metrics: time, memory, SQL queries, CPU
- Bottleneck profiling with optimization recommendations
- Fixing identified issues: XMLReader, batch writes, lock mechanism
- Re-test after optimization with confirmed results
- Documentation of limit metrics and recommended server settings

