Sizing Magento Containers by Traffic
AI generated
FROM
RUN
Docker · Magento · Sizing · Autoscaling
Sizing Magento Containers by Traffic
Deriving PHP-FPM pools, CPU limits and autoscaling with real numbers

Anyone who sets CPU and memory limits for Magento containers by gut feeling either overprovisions expensively or risks outages during traffic spikes. This article shows how Magento container sizes are systematically derived from PHP-FPM pool sizing, real memory demand per worker, and actual traffic patterns, then validated with load tests.

19 min read PHP-FPM Pool · CPU Limits · Autoscaling · Load Test Magento 2.4.8 · Docker · k6

1. Why blanket CPU and RAM limits fail

A common pattern when configuring Magento containers is setting CPU and memory limits by a blanket rule like "2 CPUs, 2 gigabytes of RAM per container," without considering the shop's actual traffic. These Magento container sizes happen to fit some shops, are massively oversized for others, and are cut too tight for yet others during traffic spikes. The result is either unnecessarily high infrastructure costs or performance drops precisely when the shop makes the most revenue.

The correct method for sizing Magento containers by traffic does not start with a resource number, but with a question: how many concurrent requests must a container be able to serve, and how much memory and CPU does a single PHP-FPM worker consume under real load. From these two values, the container size can be calculated backward instead of guessed.

This article walks step by step through the metrics needed for a sound container sizing by traffic for Magento, from PHP-FPM pool sizing through CPU limits to autoscaling rules and load tests for validation.

2. Deriving PHP-FPM pool size from traffic

The PHP-FPM pool size, meaning the number of worker processes per container, is the central lever for the Magento container size. Every worker can handle exactly one request at a time, which is why the pool size directly determines the maximum number of parallel requests per container. The formula for this is simple: desired concurrent requests divided by the number of containers gives the required pool size per container.

The critical input for this formula is the average request duration under load, not the response time at low load. A Magento request that takes 200 milliseconds at low traffic can rise to 800 milliseconds under high load due to database lock contention or CPU saturation, which reduces the effectively available capacity per worker by a factor of four. The pool size must therefore be calculated based on request duration under realistic peak load, not ideal values.


#!/usr/bin/env bash
# calculate-pool-size.sh — derive PHP-FPM pool size from target concurrency
set -euo pipefail

TARGET_CONCURRENT_REQUESTS=200
AVG_REQUEST_DURATION_MS=400
TARGET_THROUGHPUT_PER_SEC=$(( TARGET_CONCURRENT_REQUESTS * 1000 / AVG_REQUEST_DURATION_MS ))

echo "[INFO] Target throughput: ${TARGET_THROUGHPUT_PER_SEC} requests/sec"
echo "[INFO] Required pool size for ${TARGET_CONCURRENT_REQUESTS} concurrent requests: ${TARGET_CONCURRENT_REQUESTS}"
echo "[INFO] With 4 containers, pool size per container: $(( TARGET_CONCURRENT_REQUESTS / 4 ))"

3. Measuring memory demand per worker realistically

Memory per PHP-FPM worker is not a fixed constant, but depends heavily on which Magento page is being processed. A simple API request consumes noticeably less memory than a complex checkout request with many loaded modules and plugins. For a realistic container sizing, memory demand must be measured under the worst case, meaning the most memory intensive requests the shop actually serves, not the average.

The most reliable way to measure this is via docker stats during a targeted load test, combined with PHP's own metrics like memory_get_peak_usage() per request. A realistic value for a production Magento container lies between 40 and 120 megabytes per worker, depending on the number and complexity of installed modules. The container's memory limit must be at least the product of pool size and peak memory demand per worker, plus a buffer of 20 to 30 percent for PHP's own overhead processes like OPcache.


# docker-compose.yml — memory limit derived from pool size and per-worker peak usage
services:
  magento-web:
    image: registry.mironsoft.de/magento-shop:latest
    environment:
      PHP_FPM_PM_MAX_CHILDREN: "50"
    deploy:
      resources:
        limits:
          # 50 workers * 100MB peak + 25% buffer for OPcache and shared extensions
          memory: 6250M
          cpus: "4.0"
        reservations:
          memory: 4000M
          cpus: "2.0"

4. CPU limits and request latency under load

A CPU limit set too tightly for a Magento container leads to a subtle but dangerous effect: PHP-FPM workers get throttled by the container runtime as soon as the CPU quota within a time window is exhausted, causing latency spikes without CPU utilization in monitoring appearing critical at first glance. This so called CPU throttling is well documented with Kubernetes and Docker under CFS quota based limits, but is frequently overlooked in container sizing.

As a rule of thumb for Magento container sizes: at least one CPU core per eight to twelve concurrently active PHP-FPM workers, depending on how CPU intensive the respective shop's average requests are. Shops with complex pricing rules, many configurable products, or elaborate custom modules tend to need more CPU per worker than a standard catalog with simple products.

5. Traffic patterns: baseline, peak and sale events

The container size for everyday baseline load differs fundamentally from the size needed during a sale event like Black Friday. Anyone sizing Magento containers by traffic should consider these three load profiles separately: the baseline for a normal weekday, the daily peak load during rush hours in the evening, and the exceptional sale load, which can reach a multiple of the normal peak load.

A fixed container size for all three scenarios is economically inefficient, because it is either oversized for the baseline or undersized for sale events. The practical solution is a combination of conservatively sized baseline containers and an autoscaling rule that automatically starts additional container replicas once peak or sale traffic is detected, instead of always keeping maximum capacity available.

6. Horizontal vs. vertical scaling

Vertical scaling, meaning larger CPU and memory limits for the same container, has a clear drawback with Magento: it increases the capacity of a single PHP-FPM pool, but also increases the risk that a single faulty deployment or memory leak incident affects the entire vertically scaled container and therefore a larger share of total capacity. Horizontal scaling, meaning more container replicas with moderate individual size, distributes this risk and additionally allows more granular adjustment to fluctuating traffic.

For most Magento shops, horizontal scaling is the better default strategy for the web containers, because they are stateless and can be replicated arbitrarily. Vertical scaling remains sensible for services that inherently cannot scale horizontally, such as MySQL as the primary write instance or the dedicated cron container, which as described in a separate article may only have a single instance anyway.

7. Defining autoscaling rules for Magento containers

Autoscaling rules for Magento containers should primarily orient around PHP-FPM worker utilization, not exclusively raw CPU usage. A container with high CPU usage but still free PHP-FPM workers still has capacity reserves, while a container with all workers busy but moderate CPU usage is already working at the limit of concurrency and needs new replicas.

The listen queue metric from the PHP-FPM status endpoint is the most reliable indicator for this: as soon as requests land in this queue because all workers are busy, the container is effectively at its limit, regardless of the CPU percentage value. An autoscaling rule that starts an additional replica once the listen queue is greater than zero for more than 30 seconds reacts much more precisely to real capacity pressure than a pure CPU threshold rule.


# autoscale-rule.yml — scale based on PHP-FPM listen queue, not raw CPU
rules:
  - metric: php_fpm_listen_queue
    condition: "> 0"
    duration: 30s
    action: scale_up
    increment: 1
    max_replicas: 12

  - metric: php_fpm_listen_queue
    condition: "== 0"
    duration: 300s
    action: scale_down
    decrement: 1
    min_replicas: 3

  - metric: cpu_throttled_periods
    condition: "> 5%"
    duration: 60s
    action: alert
    message: "CPU limit too tight, workers being throttled"

8. Load tests to validate the sizing

Every calculated Magento container size is a hypothesis until validated under realistic load. A load test with a tool like k6 or Apache Bench that simulates the actual user flow, from category page through product page to checkout, reveals whether the calculated pool size and the set resource limits withstand reality or whether theoretical assumptions were wrong.

It is important to run the load test against an environment that resembles production as closely as possible in resource limits, data volume and network topology. A load test against a local development container without set limits provides false confidence, because it does not even show the effects of CPU throttling and memory limits that actually take effect in production.


# k6-loadtest.js — simulate realistic Magento traffic to validate container sizing
import http from "k6/http";
import { sleep, check } from "k6";

export const options = {
  stages: [
    { duration: "2m", target: 50 },   // ramp up to baseline
    { duration: "5m", target: 200 },  // sustained peak load
    { duration: "2m", target: 400 },  // sale-event spike
    { duration: "2m", target: 0 },    // ramp down
  ],
};

export default function () {
  const category = http.get("https://staging.shop.test/catalog/category/view/id/5");
  check(category, { "category status 200": (r) => r.status === 200 });

  const product = http.get("https://staging.shop.test/catalog/product/view/id/1234");
  check(product, { "product status 200": (r) => r.status === 200 });

  sleep(1);
}

9. Shop sizes and recommended container sizes compared

As a rough orientation point, an overview of typical Magento container sizes by shop category helps, understood as a starting point for your own measurements, not a replacement for load tests.

Shop size Baseline container Pool size per container Peak replicas
Small (under 1,000 orders/month) 2 CPU, 2 GB RAM 15 to 20 workers 2 to 3 replicas
Medium (1,000 to 10,000 orders/month) 4 CPU, 4 GB RAM 30 to 50 workers 4 to 6 replicas
Large (over 10,000 orders/month) 8 CPU, 8 GB RAM 60 to 100 workers 8 to 15 replicas
Sale event (any size) Baseline plus autoscaling Unchanged per container 2 to 4x the peak replicas

This table does not replace your own measurements, because module count, product complexity and custom code can shift the actual values per shop significantly. It does, however, serve as a starting point to enter your own container sizing by traffic with realistic initial values instead of starting from zero.

Mironsoft

Resource sizing for Magento infrastructure

Container sizes that actually match your traffic?

We measure PHP-FPM pool utilization and memory demand per worker in your shop, derive matching resource limits from it, and set up autoscaling rules that react to real capacity pressure instead of CPU percentages.

Traffic analysis

Deriving baseline, peak and sale patterns from real access data

Load test setup

Building realistic k6 load tests against a production-like staging environment

Autoscaling

Setting up scaling rules based on the PHP-FPM listen queue instead of CPU thresholds

10. Summary

Sizing Magento containers by traffic starts with two measurements: request duration under realistic load, from which the required PHP-FPM pool size is derived, and peak memory demand per worker, from which the container's memory limit follows. CPU limits must be generous enough to avoid CPU throttling, which otherwise causes latency spikes that remain invisible in CPU percentage monitoring.

Horizontal scaling is the more robust default strategy for stateless web containers compared to vertical scaling, because it distributes risk and reacts more granularly to load fluctuations. Autoscaling rules oriented around the PHP-FPM listen queue instead of raw CPU usage hit the actual capacity limit much more precisely. Load tests with realistic traffic patterns are the final, indispensable step to validate a calculated sizing before going into production.

Sizing Magento Containers by Traffic — Key Takeaways

Pool size

Calculate from target concurrency and request duration under real load, do not guess.

Memory limit

Pool size times peak memory demand per worker plus 20 to 30 percent buffer.

CPU limits

At least one core per eight to twelve concurrent workers, against CPU throttling.

Autoscaling

PHP-FPM listen queue as scaling signal, more precise than CPU percentages.

11. FAQ: Sizing Magento Containers by Traffic

1Why don't blanket limits work?
They happen to fit some shops, are over- or undersized for others.
2How to calculate PHP-FPM pool size?
Target concurrency divided by container count, based on request duration under peak load.
3Memory demand per worker?
40 to 120 MB, the peak value under memory intensive requests matters, not the average.
4What is CPU throttling?
Throttling once the CPU quota is exhausted, creates invisible latency spikes in CPU monitoring.
5CPU cores per worker?
Rule of thumb: one core per eight to twelve concurrently active workers.
6Horizontal or vertical scaling?
Horizontal usually better for stateless web containers, distributes risk more granularly.
7Best autoscaling metric?
PHP-FPM listen queue shows real capacity pressure more precisely than CPU percentages.
8Sizing for sale events?
More replicas via autoscaling instead of larger containers, pool size stays the same.
9Load test against local environment?
Unreliable, usually without resource limits and therefore without throttling effects.
10How often review sizing?
After module updates, catalog growth, and at least annually before the sale season.