Back to the map

Module 06 · Caching · Lesson 7 of 8

Cache stampede

When a hot key expires, every concurrent request misses at once and hits the origin together. Single-flight locks, early expiry, stale-while-revalidate and TTL jitter keep the herd from trampling the database.

DeepShould-knowSenior 15 minVideoPro Updated Nov 2026

The video walkthrough is part of Pro.

See what Pro includes
Video walkthrough · 2:16 · narrated, with captions

Why it matters

A cache turns a 10,000-request-per-second endpoint into a 100-request-per-second database load. The moment the cached key expires, the arithmetic reverses: for the few hundred milliseconds it takes one request to rebuild the value, every request misses and goes to the origin. That is a cache stampede (also called a thundering herd or dog-piling). The database that was sized for 100 requests per second gets 10,000, slows down, which makes the rebuild take longer, which lets more requests through. Outages start this way.

The idea

The problem is concurrency on a miss. One rebuild is fine; ten thousand identical rebuilds are the failure. Every mitigation does one of three things: make sure only one request rebuilds, make sure the key never fully expires while it is hot, or spread expiries out so they do not line up.

stampedereqreqreqreq ×NOriginN queries for one valuesingle-flightreqreqreqreq ×N1 rebuildwait onthe lockOrigin1 query, N responses
Without coalescing, every request during the rebuild window reaches the origin. With single-flight, one rebuilds and the rest wait for its result.

Only one rebuilds

Locking / single-flight. On a miss, try to acquire a short lock on the key (for example SET lock:key NX PX 2000 in Redis). The winner rebuilds and writes the value; the others wait briefly and re-read the cache, or serve a stale copy if one exists. Go's singleflight package and most mature cache libraries implement this in-process; a distributed lock extends it across servers. Give the lock a TTL so a crashed rebuilder cannot wedge the key.

Request coalescing at the edge. CDNs and reverse proxies do the same thing for HTTP: collapse concurrent identical requests into one origin fetch. Nginx's proxy_cache_lock and Varnish's request coalescing are this feature.

Never fully expire a hot key

Stale-while-revalidate. Keep serving the expired value for a grace period while one background request refreshes it. Users never wait on a miss, and the origin sees exactly one refresh. HTTP has a header for it; application caches implement it by storing a soft TTL alongside the hard TTL.

Probabilistic early expiration. Each request recomputes the value early with a probability that rises as the key approaches expiry, scaled by how long the recompute takes. Formally, refresh when now - delta * beta * ln(rand()) >= expiry, where delta is the recompute time (this is the XFetch algorithm). One request refreshes slightly early; the key never actually hits zero while traffic flows.

Refresh-ahead / warming. For a known hot set, a background job refreshes keys before expiry on a schedule. Simple and effective when you know the keys; the next lesson covers warming.

Spread the expiries

TTL jitter. If a deploy fills ten thousand keys at the same second with the same TTL, they expire together an hour later. Add a random few percent to every TTL so expiries smear out over time. Cheap, universal, and it prevents the synchronised version of the problem even when each individual miss is harmless.

 Single-flight lockStale-while-revalidateEarly expirationTTL jitter
Protects againstConcurrent misses on one keyAny miss on a key that has a stale copyExpiry of hot keysSynchronised expiry across keys
User-visible latency on refreshWaiters pause for the rebuildNone; stale servedNone; refreshed earlyUnchanged
Serves stale dataNo (unless combined)Yes, for the grace periodNoNo
CostA lock per missExtra memory for the stale copyA random draw per readNothing
Use whenExpensive rebuilds, strict freshnessLatency matters more than seconds of stalenessVery hot keys, steady trafficAlways
Cache stampede · Backplane