Definition · Miss window and stampedeThe miss window d of a key is the time from a miss being detected to the refilled value being available to serve — the backend call plus the write back. A stampede is the set of requests for that key which arrive during the miss window and are therefore all forwarded to the backend. Its size is λ_key·d.
λ_key is the read rate of the one key, not of the service. A service at 50 000 rps whose hottest key takes ten per cent of the traffic has λ_key = 5 000.
The formula is a rate times a time and nothing else. It does not depend on the hit rate, the cache size, the policy or the catalogue — those all describe steady state, and this is a transient. That independence is the uncomfortable part: a cache with a 99.9% hit rate has exactly the same stampede as a cache with a 50% one, for the same key at the same read rate.
Example · A hot key at five thousand reads a secondλ_key = 5 000 reads a second, d = 100 ms. The stampede is 5 000 × 0.1 = 500 requests. Against a backend that can hold 200 concurrent fills that is 5/2 = 2.50 times its capacity: the backend does not absorb this, and the requests it cannot take either queue or fail.
Scale either input and it scales linearly. The same key at a 1 ms fill sends 5 requests through; at 500 ms it sends 2 500; at 2 s, 10 000. And the fill time is the one thing you least control, because a slow fill is exactly what happens when the backend is already under pressure — which is a feedback loop, not a coincidence.
Why the obvious fixes are not fixes
A bigger cache does not help: the key was in the cache and the problem is the moment it left. A longer TTL does not help either; it makes the expiry rarer, not smaller, and TTL and Staleness has already priced what a longer TTL costs in wrongness. Nor does a higher hit rate: the hit rate is an average over a window that contains this one, and the average is fine.
Two things do help. Coalescing — also called single-flight or request collapsing — makes one request per key per window reach the backend and parks the rest on the result. And early refresh, where a request arriving near the end of a TTL refreshes the entry while continuing to serve the old value, removes the window altogether at the cost of a little more staleness.
Theorem · What coalescing is worthWithout coalescing, λ_key·d requests reach the backend per expiry. With it, exactly one does, per key. The reduction factor is λ_key·d itself.
So coalescing is worth the most precisely where the stampede is worst: the hotter the key and the slower the fill, the larger the factor. At 5 000 reads a second and a 100 ms fill it is a factor of 500.
Many keys at once, which is the version that takes systems down
A fleet that sets the same TTL on everything at deploy time expires everything together. Then k hot keys each send λ_key·d requests in the same window, and the burst is k times as large while coalescing still reduces it to k — one per key. Jittering the TTLs spreads the expiries out, and it is the cheapest of the three fixes on this page.
One limit on the model: λ·d counts arrivals in the window and assumes the backend keeps accepting them. A backend that starts queueing will make d longer, which lets more requests into the window, which makes d longer still. The formula gives the first step of that loop and not the rest of it, and the first step is already enough to size the problem.