L2 cache configuration for performance optimization
L2 (two-level) caching reduces network traffic between the remote cache service and the Commerce application by adding a local cache layer on each web node. A standard Commerce instance can transfer around 300 KB per request. At high request volumes, the resulting network traffic can be substantial.
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 that the latest cache is stored locally
- Transferring updated cache data from the remote cache service 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 cache service through a cache adapter.
The available L2 cache implementation depends on the Commerce version and patch level:
Cm_Cache_Backend_File for local storageRemoteSynchronizedCache L2 cache configuration
RemoteSynchronizedCache L2 configuration for Adobe Commerce on-premises versions before 2.4.9, where supported by the exact Commerce release and patch-level support matrix..magento.env.yaml. Do not edit app/etc/env.php directly. See Configure L2 cache.Cache configuration instructions depend on your Commerce version:
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.php file.
'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 Valkey, depending on the Commerce release and patch-level support.remote_backend_optionsis the remote cache configuration.local_backendis the local cache implementation:Cm_Cache_Backend_File.local_backend_optionsis the local cache configuration.cache_diris a file-cache-specific option that defines the directory where the local cache is stored.
For Adobe Commerce versions earlier than 2.4.9 that support Redis or Valkey, Adobe recommends using Redis or Valkey for remote caching, as supported by the exact release, and Cm_Cache_Backend_File for local caching. The local cache is commonly stored on a temporary filesystem, such as /dev/shm/:
'local_backend_options' => [
'cache_dir' => '/dev/shm/'
]
Adobe recommends using the [cache preload](redis-pg-cache.md#redis-preload-feature) feature, as it reduces the load on Redis. Ensure that you 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. The recommended cache types and trade-offs described in this section apply to both the RemoteSynchronizedCache and symfony_l2 implementations. For a symfony_l2 configuration example, see Symfony L2 cache with stale cache.
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 user 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 for the RemoteSynchronizedCache backend. For a symfony_l2 example, see Symfony L2 cache with stale cache.
'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']
],
],
Symfony L2 cache implementation
In Commerce versions 2.4.9+, use the Symfony L2 cache implementation (symfony_l2 backend) instead of RemoteSynchronizedCache. Symfony L2 cache provides a PSR-6 compliant caching implementation using Valkey.
- Adobe Commerce 2.4.9 and later
- Adobe Commerce 2.4.8-p4 and later patches
- Adobe Commerce 2.4.7-p9 and later patches
- Adobe Commerce 2.4.6-p14 and later patches
- Adobe Commerce 2.4.5-p16 and later patches
symfony_l2 for L2 caching on Adobe Commerce 2.4.9 or later, you must use Valkey for the remote cache service. See set up Valkey.Migrating from RemoteSynchronizedCache to Symfony L2
If you are upgrading an on-premises installation from the RemoteSynchronizedCache backend to symfony_l2, review the following before updating app/etc/env.php. Changing only the backend value is not sufficient. The configuration structure, key names, and some default behaviors differ.
-
The configuration structure changes.
remote_backend,remote_backend_options, andlocal_backenduse different values undersymfony_l2. For example,remote_backendbecomes'valkey'instead of a fully qualified class name. Use the configuration example below as your starting point rather than editing your existingRemoteSynchronizedCacheconfiguration in place. -
preload_keysis not recommended withsymfony_l2. If yourRemoteSynchronizedCacheconfiguration includespreload_keys, remove it as part of the migration. Preloading keys does not improve performance undersymfony_l2and can increase load on Valkey by triggering additional, unnecessary key lookups. -
Compression requires an explicit flag. Setting
compression_libalone does not enable compression undersymfony_l2. See Backend options for Symfony L2 cache for the requiredcompress_datasetting. -
Manually configured on-premises deployments do not enable stale cache by default.
use_stale_cachedefaults tofalseundersymfony_l2(see the backend options table). If yourRemoteSynchronizedCacheconfiguration used thestale_cache_enabledfrontend, you must explicitly recreate it using the pattern in Symfony L2 cache with stale cache.
VALKEY_BACKEND: symfony_l2 deploy variable have their full L2 configuration, including the stale_cache_enabled frontend, generated automatically by ece-tools. See Configure Symfony L2 cache for Cloud-specific behavior.- Redis is not a supported remote backend for
symfony_l2. Migrate to Valkey as part of this change. See set up Valkey.
Configuration example with Symfony L2 cache
app/etc/env.php example applies to on-premises installations only. For Adobe Commerce on Cloud infrastructure, do not edit app/etc/env.php directly. Set VALKEY_BACKEND: symfony_l2 in .magento.env.yaml. ece-tools generates and maintains the L2 cache configuration during deployment. See Configure Symfony L2 cache.In the app/etc/env.php file, use the simplified symfony_l2 backend type for L2 cache. This example does not include the preload_keys configuration, which is not recommended with symfony_l2. For details, see Migrating from RemoteSynchronizedCache to Symfony L2.
The example sets cleanup_percentage to 90. The default value is 95. Adjust this value according to the available local cache storage and the requirements of your Commerce deployment.
'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',
'compress_data' => '1',
'persistent_id' => 'magento_l2_default',
'timeout' => '2.5',
'read_timeout' => '2.0',
'use_lua' => '1',
],
// 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
See Stale cache options for which cache types benefit from stale cache and why.
Use the following example to configure separate frontends for symfony_l2 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',
'compress_data' => '1',
'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',
'compress_data' => '1',
'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 with Symfony L2. Redis is not officially supported.remote_backend_options[]local_backend'file'file or apculocal_backend_options[]cleanup_percentage95use_stale_cachefalsecompress_datafalsecompression_lib. Set this option in the remote Valkey backend options.persistenttruefalse ('0') to match Zend cache behavior, which defaults to non-persistent connections.frontend_options.write_control option applies to the RemoteSynchronizedCache configuration and does not apply to symfony_l2.Enhanced Symfony L2 cache performance and reliability
symfony_l2 and are available in patch ACP2E-5132.ece-tools. Update to the latest version of ece-tools to receive the latest Cloud patches during deployment.The most recent updates improve Symfony L2 cache scalability, reduce unnecessary filesystem I/O, and enhance cache consistency and reliability.
Optimized Symfony L2 cache tag storage
For Valkey-backed Symfony L2 cache deployments, cache tags are stored exclusively in Valkey. This eliminates redundant filesystem tag-index writes, reduces disk I/O, and prevents unnecessary 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.
Stale tag membership fix after retagging
Retagging a cache entry can leave it associated with tags it no longer belongs to. Stale tag memberships are now cleared on retag, so cache entries are invalidated only by the tags currently assigned to them.
Redundant remote write fix for unchanged saves
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.
L1 size-based eviction fix (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.
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 having every concurrent request rebuild the entry.
For detailed configuration options, see: