GotchaDifficulty: Advanced2 min

Cache Stampede: When a Popular Key Expires

Every request misses at the same instant, and the database takes them all.

A cache stampede happens when a value read by many requests at once expires, and every one of those requests misses together and goes to the database to rebuild it. The database receives hundreds of identical queries in the same moment, slows under them, and every page that needs it slows too.

The symptom. Every hour on the hour, the database's processor use jumps to 100% for a few seconds and the homepage times out. Between those moments everything is calm.

The trigger. The homepage is built from an expensive query, cached with a one-hour TTL, and read about 2,000 times a second. The figures below are illustrative.

One expiry of the homepage entry, illustrative timings
  1. 12:00:00.000

    The entry expires

    The next read misses.

  2. 12:00:00.001

    The first rebuild starts

    Its query takes about 200 ms.

  3. 12:00:00.200

    About 400 rebuilds are running

    Every read in those 200 ms missed too, and each started the same query.

  4. 12:00:03

    The database recovers

    The queries finish slowly under the load, and the entry is stored about 400 times.

The mechanism. Cache-aside rebuilds on a miss, and nothing stops two requests rebuilding the same key at once. While the first rebuild runs, the entry is still missing, so every request that arrives in that window misses and rebuilds too. The more popular the key and the slower the rebuild, the larger the stampede.

The cost. The busiest page fails at a predictable moment, and the load on the database can slow every other page that shares it.

The remedy. Let one request rebuild and make the rest wait for its result, often called request coalescing, done with a short lock on the key. Or keep serving the old value while one request refreshes it in the background, so readers never miss. Adding a little random jitter to TTLs stops many keys from expiring at the same instant.

So for any key read hundreds of times a second, decide before it expires which one request rebuilds it, and what the others do meanwhile.