when a single Redis key becomes a bottleneck
In heavily trafficked Magento shops, every PHP-FPM worker on a server accesses the same handful of frequently read configuration values, such as store configuration, feature flags, or layout handle mappings, which rarely change per request but get read fresh from Redis on every single request anyway. Such extremely frequently read keys are called hot keys, and even with a fundamentally performant Redis, they can become a measurable bottleneck under high load, because every single network round trip to Redis costs time that adds up noticeably across tens of thousands of requests per minute. Redis client-side caching over the RESP3 protocol promises relief here by holding hot-key values directly in the calling process's own memory, with clear but practically relevant limits for integrating it into Magento's cache backend architecture.
Table of Contents
- 1. What hot keys are and which Magento accesses typically create them
- 2. Why hot keys can become a bottleneck despite a performant Redis
- 3. RESP3 and server-assisted client-side caching in principle
- 4. Prerequisites: Redis version, RESP3, and PHP client support
- 5. Default and broadcasting mode: how tracking actually works
- 6. Practical example: holding a configuration value locally
- 7. Limits of integrating with Magento's cache backend architecture
- 8. An in-process cache layer as a pragmatic workaround
- 9. Assessing consistency risks and deciding when the effort pays off
- 10. Summary
- 11. FAQ
1. What hot keys are and which Magento accesses typically create them
A hot key is a single Redis key that gets read extremely disproportionately often relative to the total number of all accesses, frequently several orders of magnitude more often than an average key in the same dataset. In Magento, such hot keys mostly arise from values relevant to practically every request regardless of which specific product or category is being accessed, such as the serialized store configuration tree, active feature flags from a custom module, or frequently queried layout handle mappings.
The full page cache key for particularly popular pages, such as the homepage or a heavily promoted category page, can effectively become a hot key too, once a significant share of total traffic lands on that one page. The common thread across all these cases is that very many, potentially parallel PHP-FPM workers repeatedly request the same, rarely changing value from Redis within a short span of time.
2. Why hot keys can become a bottleneck despite a performant Redis
Redis itself processes individual reads extremely fast, typically in the low microsecond range, so the pure server-side processing of a hot key is rarely the actual problem. The bottleneck instead usually comes from the sum of network round trips: every single GET call requires a complete round trip over the network, including TCP overhead and, depending on deployment, TLS handshake costs for already established but freshly renegotiated connections.
With tens of thousands of requests per minute, practically every one of which queries the same hot key, this seemingly small overhead adds up to noticeable total latency and extra network load on the Redis server, even when Redis itself stays far from its CPU capacity limit. This repeated, redundant network round trip for an almost always identical value is exactly where client-side caching comes in.
3. RESP3 and server-assisted client-side caching in principle
Since Redis 6, the server supports the new response protocol RESP3 along with a feature called client-side caching, technically implemented via the CLIENT TRACKING command. Once a client enables tracking, Redis keeps server-side track of which keys that client last read, and proactively sends an invalidation message to the client whenever one of those keys changes, without the client needing to actively ask.
The client can then serve a tracked key's value directly from its own local memory until it either receives the invalidation message or removes the key from its local cache for other reasons. This pattern saves the entire network round trip to Redis on every repeated read of the same, unchanged key, as long as no change has occurred.
4. Prerequisites: Redis version, RESP3, and PHP client support
Client-side caching requires at least Redis 6, though practical stability and feature completeness have kept improving with every newer version. On the PHP side, it requires a Redis client that supports both RESP3 and CLIENT TRACKING: phpredis offers this support from correspondingly current versions onward, while for Predis, support needs to be verified depending on the version and configuration in use.
Additionally, the connection must be explicitly switched to RESP3, usually via HELLO 3 at connection setup, before CLIENT TRACKING ON can be enabled. If part of the infrastructure still runs on an older Redis version or a client without RESP3 support, for instance in a mixed deployment with several PHP versions and extension states, client-side caching simply isn't available for those components.
5. Default and broadcasting mode: how tracking actually works
In default mode, Redis keeps precise track per connection of which keys were actually read, and invalidates only those specifically once they change. That's precise, but it generates a certain amount of internal bookkeeping overhead on the server per tracked key and client, which can become noticeable with very many different, simultaneously tracked keys.
In broadcasting mode, a client instead subscribes to entire key prefixes, such as all keys under config:, and receives invalidation messages for every change within that prefix, regardless of whether the specific key was actually cached locally. For hot-key scenarios with a manageable, clearly bounded set of configuration keys, broadcasting mode is usually the more practical choice, since it noticeably reduces server-side tracking overhead.
<?php
declare(strict_types=1);
/**
* Enables RESP3 tracking in broadcasting mode for a defined
* prefix of frequently read configuration keys.
*
* @param Redis $redis Connected phpredis client with RESP3 support.
* @param string $prefix Key prefix whose changes should be tracked.
* @return void
*/
function enableBroadcastTracking(Redis $redis, string $prefix): void
{
$redis->rawCommand('HELLO', '3');
$redis->rawCommand('CLIENT', 'TRACKING', 'ON', 'BCAST', 'PREFIX', $prefix);
}
6. Practical example: holding a configuration value locally
A realistic candidate is a feature flag checked on every request, such as whether an experimental checkout layout is active. Instead of issuing a GET call against Redis on every request, a simple in-process cache holds the last read value in PHP process memory and only refreshes it once an invalidation message received through tracking signals that the value has actually changed.
What matters here is that this local cache is bound to the lifecycle of the given PHP-FPM worker connection, not to the individual request: within a long-lived PHP process, for instance with a persistent Redis client spanning several requests, the local value stays valid across multiple requests as long as no invalidation arrives, which is exactly the point of the pattern.
<?php
declare(strict_types=1);
namespace Mironsoft\HotKeyCache\Model;
use Redis;
/**
* Holds a frequently read configuration value locally and uses
* RESP3 invalidation messages to keep it current.
*/
class TrackedConfigValue
{
private ?string $cachedValue = null;
/**
* @param Redis $redis Connected phpredis client with active tracking.
* @param string $key Configuration key to track.
*/
public function __construct(private readonly Redis $redis, private readonly string $key)
{
}
/**
* Returns the current value, preferably from local memory.
*
* @return string|null
*/
public function get(): ?string
{
if ($this->cachedValue === null) {
$value = $this->redis->get($this->key);
$this->cachedValue = $value !== false ? $value : null;
}
return $this->cachedValue;
}
/**
* Invoked by the tracking callback on an invalidation message.
*
* @return void
*/
public function invalidate(): void
{
$this->cachedValue = null;
}
}
7. Limits of integrating with Magento's cache backend architecture
Magento's Cm_Cache_Backend_Redis, and the modern cache backend built on top of it, is deeply embedded in the generic Zend_Cache interface and assumes classic, stateless request-response access to the cache, not a persistently held, tracked connection with a local memory buffer. Client-side caching therefore cannot simply be enabled as a configuration option in this existing backend, but requires a dedicated, additional layer above or alongside the regular cache backend.
On top of that, PHP-FPM worker processes typically get recycled after every request or after a few requests, depending on pm.max_requests, which structurally limits the benefit of a local, process-bound cache: a freshly started worker has no local cache state built up yet and has to load the hot key from Redis regularly on first access anyway.
8. An in-process cache layer as a pragmatic workaround
Instead of deeply integrating the full RESP3 tracking protocol into Magento's cache backend, a more pragmatic approach often proves itself in practice: a simple, cross-request in-process cache within a long-lived PHP process, combined with a short, deliberately chosen TTL instead of full, event-driven tracking. That forgoes the real-time invalidation of the full RESP3 approach but is significantly simpler to implement and requires no deep change to Magento's cache architecture.
Where genuine real-time consistency is required, such as for security-relevant feature flags, RESP3 tracking can be introduced deliberately as a standalone, isolated component for exactly those few, clearly identified hot keys, instead of trying to convert the entire cache backend across the board.
9. Assessing consistency risks and deciding when the effort pays off
Any form of client-side caching inevitably introduces a time window in which a worker could theoretically serve a stale value, for instance if the invalidation message arrives late due to a brief network disruption. For uncritical, purely performance-oriented values such as layout handle mappings, this risk is usually negligible, but for security-relevant values such as access permissions or payment status, it is not readily acceptable. A deliberate classification of candidates by consistency requirement is therefore the most important step before adoption: only values where a short window of potentially stale data is tolerable should even be considered for this pattern.
Client-side caching for hot keys pays off mainly with demonstrably very high access frequency on a small, clearly identifiable set of keys, combined with infrastructure that already runs RESP3-capable Redis versions and clients. If either prerequisite is missing, or the actual access frequency of individual keys is unclear, the extra implementation and maintenance effort usually isn't justified. Before any adoption, it's worth measuring the actual access frequency of individual keys, for instance via redis-cli --hotkeys combined with an enabled maxmemory policy, or through dedicated application-level logging, to reliably distinguish genuine hot keys from accesses that merely feel subjectively frequent.
# Search Redis for actual hot keys (requires an active LFU policy)
redis-cli --hotkeys
# Check the access frequency of a specific key via OBJECT FREQ
redis-cli OBJECT FREQ "config:feature_flags
| Approach | Classic GET per request | RESP3 client-side caching | In-process TTL cache |
|---|---|---|---|
| Network round trip | On every access | Only on an actual change | Only after TTL expiry |
| Consistency | Always current | Near real-time | Stale for up to the TTL length |
| Implementation effort | None, default behavior | High, dedicated tracking layer | Low, simple TTL cache |
| Redis version | Any | At least Redis 6 with RESP3 | Any |
| Suited for | Rare, variable accesses | Few, clearly identified hot keys | Uncritical configuration values |
Mironsoft
Cache layer setup and Magento Redis integration
Magento cache that isn't quite working or is misconfigured?
We set up Redis as a cache and session backend for Magento cleanly, tune memory usage and eviction strategies, and make sure full page cache and session storage work together reliably.
Redis Setup
Configure the cache, session, and FPC backend production-ready for Magento.
Memory Tuning
Match memory usage and eviction policies to the shop's actual load.
High Availability Setup
Set up Redis Sentinel or Cluster for resilient Magento environments.
10. Summary
Client-Side Caching for Hot Keys in Magento: The Essentials at a Glance
Hot keys in Magento
Store configuration, feature flags, and layout handle mappings get read on practically every request and rarely change.
RESP3 tracking
CLIENT TRACKING lets Redis proactively send invalidation messages, so a client can use locally cached values without another network round trip.
Integration limit
Magento's existing cache backend isn't built for tracked, stateful connections and requires an additional dedicated layer.
Practical advice
A simple in-process TTL cache suffices for most cases; full RESP3 tracking pays off only for a few, clearly identified hot keys.