Load Testing for an E-commerce Store on 1C-Bitrix
A Bitrix store running smoothly with 50 concurrent visitors can crash with 500 — and the reason is not always a weak server. Heavy components, unoptimized SQL queries, absent caching — all this is revealed only under load. Load testing shows the actual throughput of the site and identifies bottlenecks before they hurt sales.
Tools
Three main tools for generating load:
Apache JMeter — de facto standard. A Java application with a GUI for creating test scenarios. Supports HTTP, HTTPS, cookies, authentication. Can record scenarios via proxy — just browse the site and JMeter saves all requests. Downside — high memory consumption with many threads; a single instance rarely generates more than 1000-2000 RPS.
Gatling — a tool written in Scala with a DSL for describing scenarios in code. Generates detailed HTML reports with graphs of response time distribution. More resource-efficient than JMeter due to non-blocking I/O. Suitable for CI/CD — the scenario is stored in the repository, run in the pipeline.
k6 — a modern tool from Grafana Labs. Scenarios are written in JavaScript, lowering the entry bar for the frontend team. Native integration with Grafana Cloud for real-time visualization. Consumes minimal resources — one machine easily generates 5000+ RPS.
| Tool | Scenario Language | Resource Consumption | Reporting | CI/CD |
|---|---|---|---|---|
| JMeter | GUI / XML | High | Plugins (JTL) | Via CLI mode |
| Gatling | Scala DSL | Medium | Built-in HTML | Native |
| k6 | JavaScript | Low | Grafana / JSON | Native |
Testing Scenarios
Load testing without realistic scenarios is a waste of time. For an e-commerce store on Bitrix, four scenarios are critical:
1. Browsing the catalog — 60-70% of traffic. Includes: homepage → catalog section → filtering by properties → product card. It's important to test with smart filter (catalog.smart.filter), which generates heavy SQL with multiple JOINs on infoblock property tables.
2. Search — 10-15% of traffic. The Bitrix search module (search) during full-text search via LIKE/MATCH accesses b_search_content — a table that becomes a bottleneck on 100,000+ products. If Elasticsearch is used via the search module or a third-party solution — test separately.
3. Cart operations — 5-10% of traffic. Adding, changing quantity, removing, applying coupon. Each action calls discount recalculation via \Bitrix\Sale\Discount\RuntimeCache — an operation that becomes noticeable with 50+ discount rules.
4. Checkout — 2-5% of traffic, but the most critical scenario. Includes: selecting delivery (calculating cost via transport company API), selecting payment, confirmation. Checkout is the heaviest process: records are created in b_sale_order, b_sale_basket, b_sale_order_props_value, b_sale_payment, event handlers are triggered.
Load distribution: scenarios are combined with weights corresponding to real traffic. In k6, this is done via scenarios with different rate for each VU group.
Key Metrics
- RPS (Requests Per Second) — the number of requests per second the site handles without degradation.
- TTFB (Time To First Byte) — time to the first byte of response. For Bitrix, acceptable TTFB is up to 200 ms for cached pages, up to 500 ms for dynamic ones.
- 95th percentile response time — the time within which 95% of requests fit. This metric, not the average, shows real user experience. If average is 200 ms but P95 is 3 seconds, every 20th visitor waits unacceptably long.
- Error rate — percentage of errors (5xx, timeouts). As load exceeds the threshold, error rate rises sharply — this is the throughput limit.
Profiling: Finding Bottlenecks
Load testing shows what is slow; profiling shows why.
Xdebug in profiling mode (xdebug.mode=profile) generates cachegrind files, which open in KCachegrind or Webgrind. Shows a call tree with execution time for each function. Downside — Xdebug slows PHP 3-5x, so profiling is done separately from load testing on single requests.
Blackfire — a commercial profiler from SensioLabs. Works as a PHP extension with minimal overhead (5-10%). Allows profiling under load, builds comparative graphs between code versions. CI/CD integration — you can set assertions: "catalog page execution time should not exceed 300 ms."
MySQL/PostgreSQL slow query log — mandatory during load testing. For MySQL: slow_query_log = 1, long_query_time = 0.5. For PostgreSQL: log_min_duration_statement = 500. Log analysis reveals queries without indexes, full table scans, deadlocks.
Typical Bitrix Bottlenecks
Heavy components without cache. catalog.section with smart filter enabled and no CACHE_TIME — each hit generates queries to b_iblock_element, b_iblock_element_property, b_catalog_price tables. On a section with 1000 products and 20 filterable properties — this is dozens of SQL queries. Solution: enable component cache (CACHE_TIME = 3600) and filter cache.
Unoptimized infoblock properties. Properties of type "List" with hundreds of values, multiple properties — each multiple property is stored as a separate row in b_iblock_element_prop_m*. When filtering by several multiple properties, MySQL/PostgreSQL builds a plan with multiple JOINs, which degrade non-linearly.
OPcache. Without OPcache, each request recompiles PHP files. Bitrix contains thousands of files — core, components, templates. Ensure: opcache.enable = 1, opcache.memory_consumption = 256 (minimum), opcache.max_accelerated_files = 20000. Check opcache_get_status() — if cache_full = true, increase memory_consumption.
Sessions in files. By default, PHP stores sessions in files. With 500+ concurrent users, the session directory contains thousands of files, and the file system slows down. Move sessions to Redis or Memcached via session.save_handler setting.
Search module. Standard Bitrix search uses the b_search_content table with FULLTEXT index. On 100,000+ products, full-text search via MySQL MATCH AGAINST becomes slow. Solution: Elasticsearch via the search module or Sphinx.
Optimization After Tests
Load test results translate into specific tasks:
| Problem | Metric | Solution |
|---|---|---|
| TTFB > 1 s on catalog | P95 response time | Component cache + composite cache |
| 5% error rate at 200 RPS | Error rate | Increase PHP-FPM workers, tune DB |
| Slow query > 2 s on filtering | Slow query log | Composite indexes, Elasticsearch |
| OOM at 300 users | Memory consumption | OPcache, module optimization |
| Timeout on checkout | TTFB checkout | Async event processing |
Load testing is not a one-time procedure. It's performed before each major sale (Black Friday, seasonal discounts), after server migration, after Bitrix core update. Automation via k6 + CI/CD allows running basic tests with each deploy and catching performance degradation early.







