Why Redis Replicas Return Expired Keys and How to Prevent It
The article explains how Redis replicas can return keys that should have expired due to the master‑only expiration process, describes the three expiration strategies (lazy, periodic, active), and offers practical solutions such as using SCAN or upgrading to Redis 3.2 to avoid stale reads.
Incident Overview
One night a developer was woken by a call: a Redis read from a replica returned a key that should have expired, causing business‑logic errors.
This is not a myth; it happens when replica nodes retain expired keys because they cannot actively delete them.
Redis Expiration Strategies
Redis provides three expiration mechanisms:
Lazy deletion : a key is removed when it is accessed after its expiration time.
Periodic deletion : a background timer scans and deletes expired keys at regular intervals.
Active deletion : when memory usage exceeds maxmemory , Redis evicts keys based on configured policies such as volatile-lru , volatile-ttl , volatile-random , allkeys-lru , allkeys-random , or disables eviction with noeviction . The number of samples for eviction decisions is controlled by maxmemory-samples (default 5).
<code>volatile-lru: evicts LRU keys with an expire set (default before Redis 3.0)
volatile-ttl: evicts keys with the shortest remaining TTL
volatile-random: evicts random keys with an expire set
allkeys-lru: evicts LRU keys from the entire dataset
allkeys-random: evicts random keys from the entire dataset
noeviction: disables eviction (default from Redis 3.0)
maxmemory-samples: number of samples for eviction decision (default 5)</code>Why Periodic Deletion Is Needed
Redis is designed as a lightweight, fast in‑memory database. Attaching a timer to every key would consume excessive resources, so deletion is performed only on the master. Replicas may therefore keep expired keys, leading to stale reads in read‑write‑separated architectures.
Active Expire Cycle
The activeExpireCycle function runs hz times per second (default 10). It randomly samples a set number of keys (typically 20) from each database, checks their expiration status, and may continue looping if more than 25% of the sampled keys are expired. The cycle respects time limits: 25 ms for normal mode and 1 ms for fast mode.
During each iteration, Redis picks a random subset of keys (e.g., 20) and evaluates them. If the proportion of expired keys exceeds 25%, the cycle repeats until the proportion falls below the threshold or the time limit is reached.
When the instance role is master , it does not delete expired keys itself; instead, it propagates a DEL command to AOF and all slaves via propagateExpire . Slaves then remove the key, making it truly unavailable.
How to Avoid Reading Stale Data from Replicas
Use the SCAN command : Scanning the keyspace triggers lazy expiration checks, reducing the chance of reading expired keys, though it adds some load.
Upgrade Redis : Starting with Redis 3.2‑rc1, the source code was modified so that lookupKeyRead returns NULL for expired keys on both master and replica when a read‑only command is executed on a replica. This effectively prevents replicas from returning stale data.
For teams that cannot modify application code, upgrading to a newer Redis version is the simplest solution.
360 Zhihui Cloud Developer
360 Zhihui Cloud is an enterprise open service platform that aims to "aggregate data value and empower an intelligent future," leveraging 360's extensive product and technology resources to deliver platform services to customers.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.