Stress testing of 1C and 1C-Bitrix exchange

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages

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 parsingSimpleXML loads the entire file into memory. A 200 MB file with memory_limit = 256M — out of memory. Solution: XMLReader for 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 SimpleXML with XMLReader — 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