ARTICLE

Tuning PHP-FPM, OPcache, and Redis for Adobe Commerce: Worker Counts, Memory, and the Settings That Actually Move Response Time

Tuning PHP-FPM, OPcache, and Redis for Adobe Commerce: Worker Counts, Memory, and the Settings That Actually Move Response Time

The settings that actually move Adobe Commerce server response time are OPcache sized to hold the whole codebase, a realpath cache, a PHP-FPM pool whose worker count matches real memory, and Redis split so the default cache, sessions, and full-page cache never share one store. Most other php.ini edits are noise.

Server tuning for Magento 2 collects a lot of folklore. Someone copies a php.ini from a blog, sets memory_limit=4G because bigger sounds safer, points Redis at one database for everything, and the store is no faster. The settings that move the number are specific and few. This guide covers them in the order of impact, with the values Adobe actually recommends, so you tune the layers that matter and leave the rest alone. Bemeir does this work on real Magento and Adobe Commerce stores, and the sequence below is how we approach a response-time ticket on the server side.

What actually moves server response time, and what does not

Response time on a cache miss is dominated by PHP execution and the work it waits on: compiling and running code, hitting the database, and reading or writing cache. Four levers control most of it.

  1. OPcache, so PHP never recompiles your code.
  2. The realpath and file-location caches, so it stops hitting the filesystem for paths.
  3. The PHP-FPM pool size, so requests are not queued waiting for a free worker.
  4. Redis layout, so cache operations are fast and do not collide.

Raising memory_limit past 1G, adding more CPU, or restarting services on a schedule rarely helps a single slow request. If you have not confirmed where the time goes, start by profiling the request before you touch any of this, because a tuned server does not fix slow custom code.

OPcache: the single highest-impact setting

OPcache keeps compiled PHP bytecode in memory so the engine does not recompile every file on every request. On a codebase the size of Adobe Commerce, this is the difference between a workable store and an unusable one, and the default OPcache memory is too small to hold it all.

Per Adobe’s software recommendations, a production OPcache looks like this:

  • opcache.memory_consumption=512
  • opcache.max_accelerated_files=60000
  • opcache.consistency_checks=0
  • opcache.validate_timestamps=0
  • opcache.enable_cli=1

The two that matter most are max_accelerated_files and validate_timestamps. Adobe Commerce has tens of thousands of PHP files, so a low file cap means OPcache evicts code and recompiles it constantly; 60000 gives it room. Setting validate_timestamps=0 tells PHP to stop checking files for changes on every request, which is the correct production setting but comes with a rule: OPcache no longer notices new code, so you must flush it on every deploy or the site serves the old files. Any deploy script has to reset PHP-FPM or call opcache_reset().

One more required value, from Adobe’s PHP settings guide: opcache.save_comments=1. Adobe Commerce 2.1 and later read PHP code comments for code generation, so stripping them breaks the application. Apply all of these to both the web server and CLI php.ini files; if your system has two, change both.

Realpath cache and APCu: small settings, real wins

PHP resolves file paths constantly, and by default it re-checks them often. Adobe recommends a realpath cache of realpath_cache_size=10M with realpath_cache_ttl=7200, documented in the realpath cache guidance, so PHP caches paths to files instead of looking them up on every page load. On a framework with this many files, that is a measurable reduction in filesystem work for the cost of two lines.

Adobe also recommends enabling APCu, which caches file locations for opened files and complements OPcache. Enable the extension and set apc.enabled=1. Neither of these is glamorous, and both pay for themselves.

Sizing the PHP-FPM pool: where your real capacity lives

OPcache makes each request cheaper. The PHP-FPM pool decides how many requests you can serve at once. Get it wrong and requests queue behind busy workers, so response time climbs under load even though a single request is fast.

The setting that controls this is pm.max_children: the maximum number of PHP worker processes. The common mistake is setting it high to “handle more traffic.” Each worker holds a full Magento process in memory, so too many workers exhaust RAM, the system swaps, and everything slows at once. Too few, and requests wait in a queue.

Size it from real memory, not a guess:

  1. Measure how much RAM a warm PHP-FPM worker actually uses. Sample the resident set size with ps under realistic load after the cache has warmed, not while the server is idle, because an idle worker understates its real footprint. Magento workers commonly run several hundred megabytes each.
  2. Subtract everything that is not PHP from total RAM: the operating system, the web server, the database if it is on the same box, and any local Redis.
  3. Divide the memory left for PHP by the per-worker figure, and use a percentile such as the 90th rather than the average so a spike does not push you into swap.

So on a web node with 8 GB free for PHP and workers that peak around 400 MB, you land near 20 children, not 100. Choose the process manager mode to match: static pre-forks a fixed pool and gives the most predictable latency when the box is dedicated to PHP; dynamic and ondemand save memory on shared boxes at the cost of spawn latency. Set pm.max_requests to a few hundred so workers recycle periodically and a slow memory leak in an extension cannot grow unbounded. Then watch the FPM status page: if the max children reached counter climbs, the pool is too small for the traffic.

Redis: split cache, session, and page cache

Redis is where a lot of stores quietly lose performance by pointing everything at one instance. Adobe’s guidance is specific: use a separate Redis instance as the default cache, use Redis for sessions, and do not use Redis for the full-page cache. Varnish is the recommended full-page cache, and the built-in PageCache module is for development only. Our walk-through of full-page cache and Varnish on Hyva covers that layer.

The reason to keep the default cache, the page cache, and sessions apart is isolation. When you flush the configuration cache, you do not want to drop every customer’s session with it, and you do not want one data type’s memory pressure evicting another’s keys. The clean layout gives each its own store, whether that is separate Redis databases on one instance or, better for busy stores, separate instances so a flush or a memory spike in one cannot touch the others. Adobe’s own Redis page cache configuration documents the env.php blocks, and the CLI equivalent is bin/magento setup:config:set with the cache, page-cache, and session flags.

A single web node that does not need to share cache across servers can skip Redis for the default cache entirely and use a RAM-backed filesystem or a socket-connected local Redis, which avoids the network hop. Reserve the multi-instance Redis setup for multi-node deployments, where it becomes the right answer. Recent note for upgrades: Magento 2.4.8 supports Redis 7.2 and Valkey, with Valkey becoming the default backend in 2.4.9, so plan the version you standardize on.

The database and kernel settings that interact with PHP

PHP tuning does not stand alone. Two neighbors matter.

On MySQL or MariaDB, Adobe recommends sizing innodb_buffer_pool_size so each of the default 8 innodb_buffer_pool_instances holds at least 1 GB, and correlating max_connections with your total PHP thread count: around 300 for a small environment and 1000 for a medium one. If every PHP worker can open a database connection, the database must allow at least as many as all your workers combined, or requests fail under load. It also suggests innodb_thread_concurrency = 2 * (NumCPUs + NumDisks) as a starting point.

At the kernel level, Adobe lists net.core.somaxconn=1024 and net.ipv4.tcp_tw_reuse=1 to keep the connection queue from capping throughput under bursty traffic. And enable the pcntl PHP extension, because Magento uses it to run indexers in parallel mode, which matters when reindexing competes with live traffic. If reindexing or the consumer queue is your actual bottleneck rather than request handling, cron and indexer health is the better place to look, and heavy traffic events have their own playbook in scaling for flash sales and product drops.

A production baseline at a glance

Setting Recommended value Why it matters
opcache.memory_consumption 512 Holds the full compiled codebase in memory
opcache.max_accelerated_files 60000 Stops OPcache evicting and recompiling Magento’s many files
opcache.validate_timestamps 0 (flush on deploy) Skips per-request file checks in production
opcache.save_comments 1 Required; Commerce reads comments for code generation
realpath_cache_size / ttl 10M / 7200 Caches file paths instead of resolving them each load
memory_limit 1G (2G for debugging) Enough headroom without encouraging waste
pm.max_children RAM for PHP divided by p90 worker RSS Caps concurrency to avoid swapping
Default cache Redis, separate instance Fast, shared across nodes, isolated from sessions
Sessions Redis, separate store Survive a cache flush
Full-page cache Varnish, not Redis Adobe’s recommended production FPC

The order to tune in

Tune OPcache and the realpath cache first, because they help every request and cost nothing in hardware. Size the PHP-FPM pool next, from measured memory, so you stop queuing under load. Then set up Redis correctly and confirm Varnish is doing the full-page caching. Adjust the database and kernel settings last, once the PHP layer is right. Change one thing, measure the same request, and keep what moves the number.

This server work is one half of a fast store. The other half is the frontend, which is why much of our performance work pairs a tuned backend with a Hyva frontend, and the same discipline applies whether a client runs Adobe Commerce or sells on Shopify, Shopware, or BigCommerce. The hosting and caching tools we reach for come out of our technology partner ecosystem, and the infrastructure choices behind them are covered in Hyva on AWS infrastructure decisions.

If your Adobe Commerce store is slow under load and you want the server tuned by people who do it every week, Bemeir can help, and you can read more about Bemeir and how we work with merchant teams.

FAQ

What is the most important single setting to fix first?

OPcache memory and file count. On Adobe Commerce, an undersized OPcache forces constant recompilation and makes every page slow. Set opcache.memory_consumption=512 and opcache.max_accelerated_files=60000, confirm the whole codebase fits with room to spare, and you have addressed the biggest single lever before anything else.

How do I choose pm.max_children for my server?

Measure real memory, do not guess. Sample a warm PHP-FPM worker’s resident memory under load, subtract the operating system, web server, and database from total RAM, and divide the remainder by the per-worker figure using a high percentile. On Magento that often lands near 20 to 30 workers per node, far below the triple-digit values people copy from generic tutorials.

Should I use Redis for the full-page cache?

No. Adobe recommends Varnish as the production full-page cache and treats the built-in PageCache module as development only. Use Redis for the default cache and for sessions, each in its own store, and let Varnish handle full-page caching so you are not holding two copies of the same cached HTML.

Why did my site serve old code after a deploy?

Because opcache.validate_timestamps=0 tells PHP to stop checking files for changes, which is correct for production but means OPcache keeps serving the previously compiled code. Your deploy process must flush OPcache, by restarting PHP-FPM or calling opcache_reset(), so new code takes effect.

Does raising memory_limit make Magento faster?

Not on its own. memory_limit is a ceiling per request, not an allocation, so setting it to 4G does not speed up a page that only needs 300 MB. Adobe recommends 1G for normal operation and 2G for debugging. Oversizing it only hides memory leaks and lets a runaway request consume more before it fails.

Let us help you get started on a project with Tuning PHP-FPM, OPcache, and Redis for Adobe Commerce: Worker Counts, Memory, and the Settings That Actually Move Response Time and leverage our partnership to your fullest advantage. Fill out the contact form below to get started.

more articles about ecommerce

Read on the latest with Shopify, Magento, eCommerce topics and more.