Redis Caching Patterns
Caching is the most common reason teams adopt Redis. Putting frequently read data in memory, in front of a slower database or API, can turn 50 ms queries into sub-millisecond lookups and absorb traffic that would otherwise overwhelm your primary store. But a cache adds a second copy of your data, and with it every hard problem in caching: staleness, invalidation, thundering herds, and memory limits.
This page covers the standard patterns for reading and writing through Redis, how to choose TTLs and eviction policies, and how to avoid the failure modes that turn a cache into an outage amplifier.
TL;DR
- Cache-aside (lazy loading) is the default: read from Redis, and on a miss load from the database and populate the cache.
- Write-through updates the cache on every write; write-behind writes to the cache first and persists asynchronously (riskier).
- Every cache key needs a TTL. Add random jitter so keys don't all expire together.
- On writes, delete (invalidate) the key rather than updating it, to avoid races that leave stale data.
- Configure
maxmemoryand an eviction policy (allkeys-lruorallkeys-lfufor pure caches). - Protect hot keys from cache stampedes with request coalescing, locks, or early recomputation.
Quick Example
Cache-aside in Python with TTL jitter and invalidation on update:
The next read after an update misses and reloads fresh data from the database.
Core Concepts
Read Patterns
Write Patterns
For most applications, cache-aside plus invalidate-on-write is the right default.
TTL Strategy
TTLs bound staleness and let unused data age out:
- Choose TTLs by how stale data may be: seconds for prices or inventory, minutes for profiles, hours for reference data.
- Add jitter (±10–20%) so keys written together don't expire together.
- Even with explicit invalidation, keep a TTL as a safety net for missed invalidations.
Eviction Policies
When Redis reaches maxmemory, the maxmemory-policy decides what to remove:
A dedicated cache instance with allkeys-lfu or allkeys-lru is simpler and safer than mixing cache and durable data on one instance.
Cache Stampedes
When a hot key expires, hundreds of concurrent requests miss at once, all hit the database, and all try to rebuild the same value. This is the thundering herd or dog-pile effect. Defenses:
- Request coalescing / locking: the first miss acquires a short lock (
SET lock:key token NX PX 5000) and rebuilds; others wait briefly and retry the cache, or serve the stale value. - Stale-while-revalidate: store a soft expiry inside the value, and serve stale data while one worker refreshes in the background.
- Probabilistic early expiration: each reader has a small, growing chance of refreshing before the hard TTL, which spreads rebuilds out.
- TTL jitter: stops mass expirations after a deploy or bulk load.
Consistency Pitfalls
Caches are eventually consistent by nature. Common races:
- Update-then-set race: two writers update the DB in one order and the cache in the opposite order, leaving the older value cached. Deleting instead of setting avoids most of this.
- Read-populate race: a reader loads an old value from the DB, a writer updates the DB and deletes the key, and the reader then writes the old value into the cache. Short TTLs bound the damage; versioned values or delayed double-delete reduce it further.
- Replication lag: loading from a read replica right after a write can cache stale data. Read from the primary when repopulating after writes.
For strong cross-system consistency, drive invalidation from the database's change stream using change data capture.
Best Practices
Treat the Cache as Disposable
Your application must work, more slowly, with an empty or unavailable cache. Wrap Redis calls with timeouts and fall back to the source of truth on errors, so a cache outage doesn't become a full outage.
Cache at the Right Granularity
Cache the expensive thing: a rendered fragment, an aggregated query result, or an external API response. Caching tiny rows individually can create more round trips than it saves.
Monitor Hit Rate and Memory
Track keyspace_hits/keyspace_misses, evictions, memory use, and latency. A falling hit rate or rising evictions means keys, TTLs, or memory need attention.
Consider Client-Side Caching for Very Hot Keys
Redis supports server-assisted client-side caching (CLIENT TRACKING): clients keep a local copy and Redis notifies them on change. It removes network round trips entirely for extremely hot keys.
Common Mistakes
Caching Without a TTL
Keys with no expiry accumulate forever, and one missed invalidation serves stale data indefinitely. Every cache write should set an expiry.
Caching Errors and Empty Results Carelessly
Caching "not found" (negative caching) protects the DB from repeated lookups for missing items, but use a short TTL. Never cache transient errors like timeouts as if they were real results.
Putting Sessions or Queues on an Evicting Cache
If the instance uses allkeys-lru, it may evict session data or queued jobs under memory pressure. Keep durable data on a separate instance with noeviction and persistence enabled; see Redis persistence.
FAQ
Should I update or delete the cache on writes?
Delete. Updating the cache from the write path creates ordering races between concurrent writers and can leave an older value cached. Deleting forces the next reader to load the latest committed data. Combine it with a TTL as a safety net.
What TTL should I use?
As long as the business can tolerate stale data, and no longer. Start with minutes for most entity caches, seconds for fast-changing values, and add jitter. Measure hit rates and adjust; very short TTLs on cold data mostly add misses.
Redis or an in-process cache?
In-process caches (a local LRU map) are faster, with no network hop, but each instance holds its own copy and invalidation across instances is hard. Redis provides one shared cache for all instances. Many systems use both: a tiny short-TTL local cache in front of Redis.
How do I cache in a Redis Cluster?
The same patterns apply. Keys spread across shards by hash slot. Keep multi-key operations (MGET, transactions) on keys that share a slot by using hash tags like {user:42}:profile. See Redis Cluster.
Related Topics
- Redis — The database overview
- Caching — Caching principles and invalidation
- Caching Layers — CDN, application, and database caches together
- Redis Data Structures — Choosing value types for cached data
- Redis Persistence — When data must survive restarts
- Performance Optimization — Where caching fits