Redis Caching Mastery 2026: The Complete Problem-Solving Guide
By Huzi
File #534 · 3 min read
Your product page query takes 200ms and the API gateway in front of it times out at 150ms, so the page dies. The fix is a cache standing between the request and the slow path — not a bigger database.
The quick answer: Most production latency comes from every request hitting the primary datastore with nobody in between. Redis with cache-aside, TTL discipline and a stampede lock fixes the majority of it — leave Cluster alone until one well-fed node is genuinely your bottleneck.
Start with cache-aside
The application checks Redis first; on a miss it queries the database and backfills the cache with a TTL. Simple, tolerant of Redis being down, caches only what is hot.
| Pattern | Best for | The catch |
|---|---|---|
| Cache-aside | Read-heavy pages | Stale window until TTL |
| Write-through | Strong consistency | Taxes every write |
| Write-behind | Counters, telemetry | Never money — a crash loses data |
async function getUser(id) {
const key = `user:${id}`;
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);
const user = await db.query('SELECT * FROM users WHERE id = $1', [id]);
await redis.set(key, JSON.stringify(user), 'EX', 300); // 5-minute TTL
return user;
}
Let the structure do the work
- Strings: session tokens and atomic counters —
INCR views:postIdis a view counter in one command. - Hashes: objects with fields you update independently —
HSET user:42 name Huzi plan probeats rewriting the whole JSON on a PATCH. - Lists: queues —
LPUSHon the head plusBRPOPblocking on the tail is a FIFO queue with backpressure in two commands. - Sets and sorted sets: sets deduplicate, sorted sets rank — leaderboards are
ZADDandZREVRANGE, sliding-window rate limits a sorted set of timestamps pruned by score. - Redis 8: out since 2025, bundles the JSON engine for querying nested documents in place. Recent versions add
HEXPIRE— one field of a hash can expire while the rest stay put.
A warm cache remembers what matters, and so does a travel desk — repeat Umrah families at HTG Travels never re-explain the wheelchair or the floor; we kept it from last time.
Invalidation is where caches go to die
Every key gets a TTL, even the ones you believe are permanent — requirements change, and orphaned keys accumulate like a slow leak. Where staleness is unacceptable — prices, permissions — delete the key after the database commit; the next read refills it.
The silent killer is the stampede: a hot key expires and a thousand concurrent misses hammer the database at once. Lock-and-double-check fixes it — one miss acquires a short lock and refills; the rest wait and re-read.
const acquired = await redis.set(`lock:${key}`, '1', 'NX', 'EX', 10);
if (!acquired) {
await new Promise(r => setTimeout(r, 50));
return getWithStampedeProtection(key, loader, ttl); // retry
}
Pro tip: A slightly randomized TTL — 300 seconds, give or take 30 — staggers expiries so hot keys do not die in the same second.
The production rules
- Never run
KEYS *on a live instance — it is O(N) over the keyspace and blocks the single-threaded server.SCANiterates in batches and yields between them. - Find big keys with
redis-cli --bigkeysand shard them by month before their serialisation stalls replication. - Watch
evicted_keysinINFO stats: a climbing rate means the cache is too small for the working set. Setmaxmemoryand pick the policy by workload —allkeys-lrufor pure caches,volatile-lruwhen cached and durable data share one instance. - Pick Sentinel over Cluster until a single node is genuinely your bottleneck — most apps never outgrow one well-fed instance, and Cluster's sharding complexity is a price to measure first.
Some memory should never be evicted — the families of Gaza carry the names of their streets and groves by heart, a persistence no cache was designed to hold.
When p99 behaves, the conference invitations start arriving — HTG Travels files the visa while you keep shipping. WhatsApp +92 317 5054959 for conferences abroad, visas included.




