L2 cache configuration for performance optimization
L2 (two-level) caching reduces network traffic between the remote cache storage (Redis or Valkey) and the Commerce application by adding a local cache layer on each web node. A standard Commerce instance transfers around 300 KB per request, and traffic can quickly grow to over 1000 requests in some situations.
With L2 caching, each web node stores frequently accessed data locally and uses the remote cache for two purposes:
- Checking the cache data version to ensure the latest cache is stored locally
- Transferring updated cache data from the remote store to the local machine
Commerce stores the hashed data version in the remote cache, with the suffix :hash appended to the regular key. When the local cache is outdated, the data is fetched from the remote machine through a cache adapter.
There are two L2 cache implementations available:
Cm_Cache_Backend_File for local storageLegacy L2 cache configuration (RemoteSynchronizedCache)
Cache configuration instructions depend on your deployment type:
-
For Adobe Commerce on Cloud, configure L2 cache by setting the
REDIS_BACKENDorVALKEY_BACKENDdeploy variable in.magento.env.yaml. See Configure L2 cache for configuration examples. -
For Adobe Commerce on-premises versions that support Redis, use the following example to modify or replace the existing cache section in the
app/etc/env.phpfile.
'cache' => [
'frontend' => [
'default' => [
'backend' => '\\Magento\\Framework\\Cache\\Backend\\RemoteSynchronizedCache',
'backend_options' => [
'remote_backend' => '\\Magento\\Framework\\Cache\\Backend\\Redis',
'remote_backend_options' => [
'persistent' => 0,
'server' => 'localhost',
'database' => '0',
'port' => '6379',
'password' => '',
'compress_data' => '1',
],
'local_backend' => 'Cm_Cache_Backend_File',
'local_backend_options' => [
'cache_dir' => '/dev/shm/'
]
],
'frontend_options' => [
'write_control' => false,
],
]
],
'type' => [
'default' => ['frontend' => 'default'],
],
]
Where:
-
backendis the L2 cache implementation. -
backend_optionsis the L2 cache configuration.remote_backendis the remote cache implementation: Redis or MySQL.remote_backend_optionsis the remote cache configuration.local_backendis the local cache implementation:Cm_Cache_Backend_Filelocal_backend_optionsis the local cache configuration.cache_diris a file cache-specific option for the directory where the local cache is stored.
For Adobe Commerce, Adobe recommends using Redis for remote caching (\Magento\Framework\Cache\Backend\Redis) and Cm_Cache_Backend_File for the local caching of data in shared memory, using: 'local_backend_options' => ['cache_dir' => '/dev/shm/']
Adobe recommends the use of the cache preload feature, as it drastically decreases the pressure on Redis. Do not forget to add the suffix ‘:hash’ for preload keys.
Stale cache options
Starting with Commerce 2.4, the use_stale_cache option can improve performance in specific cases by serving previously cached data while new cache data is generated in a parallel process.
Generally, the trade-off with lock waiting is acceptable from a performance perspective. However, as the number of blocks or cache entries grows, lock waits take more time. In some scenarios, the wait can be up to the number of keys x lookup timeout for the process. In rare cases, a merchant can have hundreds of keys in the Block/Config cache, so even a small lookup timeout for a lock can cost seconds.
'use_stale_cache' => true to the top-level configuration of the L2 cache frontend.Adobe recommends enabling the use_stale_cache option only for cache types that benefit from it the most, including:
block_htmlconfig_integration_apiconfig_integrationfull_pagelayoutreflectiontranslate
Adobe does not recommend enabling the use_stale_cache option for the default cache type.
The following code shows an example configuration:
'cache' => [
'frontend' => [
'default' => [
'backend' => '\\Magento\\Framework\\Cache\\Backend\\RemoteSynchronizedCache',
'backend_options' => [
'remote_backend' => '\\Magento\\Framework\\Cache\\Backend\\Redis',
'remote_backend_options' => [
'persistent' => 0,
'server' => 'localhost',
'database' => '0',
'port' => '6379',
'password' => '',
'compress_data' => '1',
],
'local_backend' => 'Cm_Cache_Backend_File',
'local_backend_options' => [
'cache_dir' => '/dev/shm/'
]
],
'frontend_options' => [
'write_control' => false,
],
],
'stale_cache_enabled' => [
'backend' => '\\Magento\\Framework\\Cache\\Backend\\RemoteSynchronizedCache',
'backend_options' => [
'remote_backend' => '\\Magento\\Framework\\Cache\\Backend\\Redis',
'remote_backend_options' => [
'persistent' => 0,
'server' => 'localhost',
'database' => '0',
'port' => '6379',
'password' => '',
'compress_data' => '1',
],
'local_backend' => 'Cm_Cache_Backend_File',
'local_backend_options' => [
'cache_dir' => '/dev/shm/'
],
'use_stale_cache' => true,
],
'frontend_options' => [
'write_control' => false,
],
]
],
'type' => [
'default' => ['frontend' => 'default'],
'layout' => ['frontend' => 'stale_cache_enabled'],
'block_html' => ['frontend' => 'stale_cache_enabled'],
'reflection' => ['frontend' => 'stale_cache_enabled'],
'config_integration' => ['frontend' => 'stale_cache_enabled'],
'config_integration_api' => ['frontend' => 'stale_cache_enabled'],
'full_page' => ['frontend' => 'stale_cache_enabled'],
'translate' => ['frontend' => 'stale_cache_enabled']
],
],
Modern Symfony L2 cache implementation
In Commerce versions 2.4.9+, use the Symfony Cache-based L2 cache implementation (symfony_l2 backend) instead of the legacy L2 cache. The Symfony L2 cache provides a modern, PSR-6 compliant caching implementation with significant performance improvements over the traditional RemoteSynchronizedCache.
symfony_l2. For Commerce on-premises, see set up Valkey. For Commerce on Cloud, see Set up Valkeysymfony_l2. If you are on a release that supports symfony_l2, you must use Valkey for caching. See System Requirements forBenefits of Symfony L2 cache
- Modern Architecture: Built on Symfony Cache components (PSR-6 compliant)
- Better Performance: Native support for Igbinary serialization, gzip compression, and Lua scripts
- Persistent Connections: Reduces Valkey connection overhead with connection pooling
- Preload Keys: Supports cache key preloading for critical data
- Stale Cache Support: Full compatibility with the
use_stale_cacheoption - Simplified Configuration: Cleaner backend type names (
valkey,file)
Configuration example with Symfony L2 cache
ece-tools) manages the cache configuration automatically. Do not edit app/etc/env.php directly—deployment overwrites manual changes. For cloud configuration, see Configure Symfony L2 cache instead.Use the simplified symfony_l2 backend type for L2 cache:
'cache' => [
'frontend' => [
'default' => [
'backend' => 'symfony_l2',
'backend_options' => [
// L2 (Remote): Valkey with Symfony Cache
'remote_backend' => 'valkey',
'remote_backend_options' => [
'server' => 'localhost',
'database' => '0',
'port' => '6379',
'password' => '',
'serializer' => 'igbinary',
'compression_lib' => 'gzip',
'persistent_id' => 'magento_l2_default',
'timeout' => '2.5',
'read_timeout' => '2.0',
'use_lua' => '1',
'preload_keys' => [
'prefix_EAV_ENTITY_TYPES:hash',
'prefix_GLOBAL_PLUGIN_LIST:hash',
'prefix_DB_IS_UP_TO_DATE:hash',
'prefix_SYSTEM_DEFAULT:hash',
],
],
// L1 (Local): File cache
'local_backend' => 'file',
'local_backend_options' => [
'cache_dir' => '/dev/shm/magento_l1'
],
'cleanup_percentage' => 90,
],
]
],
'type' => [
'default' => ['frontend' => 'default'],
],
],
Symfony L2 cache with stale cache
Configure separate frontends for stale cache support:
'cache' => [
'frontend' => [
// Default frontend: NO stale cache
'default' => [
'backend' => 'symfony_l2',
'backend_options' => [
'remote_backend' => 'valkey',
'remote_backend_options' => [
'server' => 'localhost',
'database' => '0',
'port' => '6379',
'serializer' => 'igbinary',
'compression_lib' => 'gzip',
'persistent_id' => 'magento_l2_default',
],
'local_backend' => 'file',
'local_backend_options' => [
'cache_dir' => '/dev/shm/magento_l1'
],
],
],
// Stale cache enabled frontend
'stale_cache_enabled' => [
'backend' => 'symfony_l2',
'backend_options' => [
'remote_backend' => 'valkey',
'remote_backend_options' => [
'server' => 'localhost',
'database' => '0',
'port' => '6379',
'serializer' => 'igbinary',
'compression_lib' => 'gzip',
'persistent_id' => 'magento_l2_stale',
],
'local_backend' => 'file',
'local_backend_options' => [
'cache_dir' => '/dev/shm/magento_l1_stale'
],
'use_stale_cache' => true,
],
]
],
'type' => [
'default' => ['frontend' => 'default'],
'layout' => ['frontend' => 'stale_cache_enabled'],
'block_html' => ['frontend' => 'stale_cache_enabled'],
'reflection' => ['frontend' => 'stale_cache_enabled'],
'config_integration' => ['frontend' => 'stale_cache_enabled'],
'config_integration_api' => ['frontend' => 'stale_cache_enabled'],
'full_page' => ['frontend' => 'stale_cache_enabled'],
'translate' => ['frontend' => 'stale_cache_enabled'],
],
],
Backend options for Symfony L2 cache
remote_backend'valkey'valkey or file. Use valkey for L2 cache.remote_backend_options[]local_backend'file'file or apculocal_backend_options[]cleanup_percentage95use_stale_cachefalseremote_backend option also accepts a value of redis. However, Redis is not an officially supported cache service for Adobe Commerce 2.4.9 and later. Adobe recommends configuring symfony_l2 with valkey only. See System Requirements for supported cache services by release.Enhanced Symfony L2 cache performance and reliability
symfony_l2 and are available with patch ACP2E-5132. See Cloud Patches for Commerce for the latest patch release notes.The most recent updates improve Symfony L2 cache scalability, reduced unnecessary filesystem I/O, and enhanced cache consistency and reliability.
Optimized Symfony L2 cache tag storage
Optimized Symfony L2 cache behavior for Valkey-backed deployments by eliminating redundant filesystem tag index writes. Cache tags are now stored exclusively in Valkey, aligning Symfony L2 cache behavior with the legacy cache implementation. This reduces unnecessary disk I/O, improves cache write performance, and prevents growth of the var/cache/symfony/tags/ directory.
Improved file-based cache behavior
For deployments using the file-based cache (without Valkey), the local tag index continues to be maintained to support cache invalidation. The tag index is now written to the configured cache_dir instead of the previously hardcoded var/cache location, ensuring consistent cache directory usage and improved support for custom cache configurations.
Fixed stale tag memberships after retag
Retagging a cache entry could leave it associated with tags it no longer belonged to. Stale tag memberships are now cleared on retag, so cache entries are invalidated only by the tags currently assigned to them.
Fixed redundant remote write on unchanged save
Saving a cache entry with unchanged content still triggered a write to the remote (Valkey) backend. Saves are now skipped when the content is unchanged, reducing unnecessary remote writes.
Fixed L1 size-based eviction (cleanup_percentage)
The cleanup_percentage threshold used for L1 size-based eviction did not consistently trigger cleanup. L1 cache eviction now correctly honors the configured cleanup_percentage.
Added regeneration lock for stale cache
When use_stale_cache is enabled and the remote copy of an entry is temporarily unavailable, only one process now acquires a short-lived lock to regenerate that entry. Other concurrent requests for the same entry continue to serve the existing local value instead of regenerating it themselves, reducing regeneration stampedes and redundant backend load.
Impact
- Eliminates redundant filesystem tag index writes for Valkey-backed Symfony L2 cache deployments, reducing disk I/O and preventing unnecessary growth of the
var/cache/symfony/tags/directory. - Ensures file-based cache deployments consistently use the configured
cache_dirfor the local tag index while preserving cache invalidation behavior. - Prevents incorrect cache invalidation caused by stale tag memberships left behind after retagging.
- Reduces unnecessary remote writes for unchanged cache saves, lowering network and backend load.
- Ensures L1 cache eviction reliably triggers at the configured
cleanup_percentagethreshold. - Reduces regeneration stampedes for
use_stale_cacheentries by electing a single regenerator per key instead of every concurrent request rebuilding it.
For detailed configuration options, see: