Client-Side Caching for Hot Keys in Magento Shops With Redis
AI generated
SET
TTL
Redis / RESP3 Client-Side Caching
Client-Side Caching for Hot Keys in Magento Shops
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.

12 min read RESP3 tracking Hot keys In-process cache

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.

11. FAQ: Client-Side Caching for Hot Keys in Magento: The Essentials at a Glance

1What exactly is a hot key in the Redis context?
A single key that gets read extremely disproportionately often relative to all other keys, frequently several orders of magnitude more often than an average key.
2Which Magento values typically become hot keys?
Mainly values relevant to practically every request, such as store configuration, active feature flags, or layout handle mappings, as well as full page cache entries for very popular pages.
3Why does a hot key become a problem even though Redis itself is very fast?
It's not server-side processing that's the problem, but the sum of network round trips from very many repeated accesses to the same, barely changing value.
4What exactly is RESP3 client-side caching?
A feature available since Redis 6 via CLIENT TRACKING, where Redis proactively sends invalidation messages to clients as soon as a key they read changes.
5What prerequisites does client-side caching need?
At least Redis 6, a connection switched to RESP3 via HELLO 3, and a PHP Redis client with corresponding support for tracking.
6What's the difference between default and broadcasting mode?
Default mode tracks precisely the individual keys that were read, while broadcasting mode subscribes to entire key prefixes, reducing server-side bookkeeping overhead with many keys.
7Why can't client-side caching simply be enabled in Magento's cache backend?
The existing cache backend is built on stateless request-response access, not a persistently held, tracked connection with a local memory buffer, and therefore requires an additional layer.
8What's a pragmatic alternative to full RESP3 tracking?
A simple in-process cache with a short TTL within a long-lived PHP process, which forgoes real-time invalidation but is significantly simpler to implement.
9What consistency risk does client-side caching carry?
A short time window in which a worker could theoretically serve a stale value, for instance from a delayed invalidation message, which is usually negligible for uncritical values.
10How can genuine hot keys be distinguished from subjectively frequent accesses?
Via redis-cli --hotkeys with an enabled LFU maxmemory policy, or via OBJECT FREQ for individual keys, supplemented by dedicated application-level logging.