Redis path · Using it well · Topic 4 of 11

Caching patterns and stampedes

Not started

The most common use of Redis is as a cache in front of a slower database. The idea is simple: keep the answer to an expensive question in memory for a while. The details decide whether it helps. When is a cached value filled? What happens on a write? And what happens when a popular key expires and thousands of requests miss at the same moment?

Why it matters: A cache that is wrong or that collapses under a burst of misses can do more harm than no cache at all.

  1. 1Cache-aside

    The application reads the cache, and on a miss loads from the database and stores the result with a TTL.

  2. 2Write-through

    Writes go to the cache and the database together, so reads find fresh data, at the cost of caching data nobody reads.

  3. 3Invalidate by deleting

    After a database write, delete the cache key rather than setting it; the next read reloads it from the source.

  4. 4Stampedes

    When a hot key expires, every request misses at once and all of them hit the database; collapse them into one load.

1

How it works

The explanation, with examples you can run.

Cache-aside

The application owns the logic. Read from the cache; on a miss, load from the database, store with a TTL, return.

GET product:7                    # miss: (nil)# ...application queries the database...SET product:7 '{"id":7,"name":"Kettle","price":2900}' EX 300GET product:7                    # hit for the next five minutes

Only data that is actually read gets cached, and if Redis is down the application can still fall back to the database (slower). The cost is that the first read after a miss is slow, and cached data can be stale for up to the TTL.

Write-through and write-behind

  • Write-through: every write updates the database and the cache together, so reads are always fresh. Everything written is cached, read or not.
  • Write-behind: write to the cache, and copy to the database later. Fast writes, but anything not yet copied is lost if the cache fails. Rarely worth it for data you cannot lose.

Invalidation

When the source changes, the simplest robust rule is: write the database, then delete the key.

DEL product:7

Setting the new value from the writer instead invites races: two writers can update the cache in the opposite order to their database commits, leaving the older value cached until the TTL ends. Deleting is not perfect either (a reader that loaded the old row just before the write can store it after the delete), which is why a TTL is the safety net in every pattern.

Stampedes

When a hot key expires, every request that arrives before it is reloaded misses, and each one runs the expensive query. This simulation sends 200 concurrent requests for a just-expired key:

⌘/Ctrl + Enter
OutputNot run yet

Press Run to see what your code prints, in order.

Runs in this browser, in an isolated frame with no access to this page. console.log, info, warn and error are shown; code runs as a classic script, so use an async function for await.

Single flight works within one process. Across many application instances, the usual tools are:

  • A short lock in Redis: the first instance to SET lock:product:7 <token> NX PX 5000 reloads the value; the others briefly serve the stale copy or retry.
  • Early refresh: reload a popular key before it expires (for example, when its remaining TTL drops below some fraction, with a bit of randomness so instances do not all refresh together).
  • Jittered TTLs, so keys written together do not expire together.
  • Stale-while-revalidate: keep the old value a little longer and serve it while one request refreshes it.

What to cache

Cache what is read far more often than it changes, and size the TTL by how stale it may be. Track the hit ratio (keyspace_hits and keyspace_misses in INFO stats): a cache with a low hit ratio adds a network hop to every request and saves little.

2

Check yourself

3 questions. Get them all right to finish this topic.

  1. 1.A product page key with 10,000 requests a second expires. Each miss runs a 200 ms query. With plain cache-aside, what happens?
  2. 2.After updating a product in the database, why do many teams DEL the cache key instead of SETting the new value?
  3. 3.When does write-through make more sense than cache-aside?

0 of 3 right so far. Get all three to finish this topic.