Caching PatternsLesson 3.5
Preventing cache stampede with Redis locks and probabilistic early expiration
cache stampede definition, mutex lock with SET NX, lock timeout, probabilistic early expiration algorithm, XFetch formula, dog-pile effect
The cache stampede problem
A cache stampede (dog-pile effect) happens when a popular cache key expires and many concurrent requests all miss and simultaneously query the database.
Mutex lock approach
async function getProductSafe(id) {
const key = `product:${id}`;
const cached = await client.get(key);
if (cached) return JSON.parse(cached);
const lockKey = `lock:${key}`;
const acquired = await client.set(lockKey, '1', { NX: true, EX: 5 });
if (!acquired) {
// Another process is fetching — wait and retry
await new Promise(r => setTimeout(r, 50));
return getProductSafe(id);
}
const data = await db.getProduct(id);
await client.setEx(key, 300, JSON.stringify(data));
await client.del(lockKey);
return data;
}Probabilistic early expiration (XFetch)
Recompute the cache before it expires, probabilistically. The closer to expiry, the higher the chance of early refresh. No locks needed.
function shouldRefresh(ttl, beta = 1) {
const delta = Math.random() * beta * Math.log(Date.now());
return delta > ttl;
}
// If shouldRefresh returns true, recompute before the key expiresXFetch is simpler under very high concurrency. Use mutex locks for jobs where you absolutely cannot afford duplicate DB queries.
