BytewizeJoin the waitlist

Cache-aside vs read-through

Two ways to fill a cache on a miss, and what changes when the cache does the loading.

5 minute lesson

Who loads the data on a miss?

Both patterns put a cache in front of the database. The difference is who fetches from the database when the cache misses: your code (cache-aside) or the cache itself (read-through).

Key terms

cache-aside
The application checks the cache, loads from the database on a miss and populates the cache itself.
read-through
The application reads only from the cache; on a miss the cache calls a registered loader to fetch the value.
loader
A function you register with the cache that knows how to fetch a value for a key.

Cache-aside in seven lines

products.ts
async function getProduct(id) {
  const hit = await cache.get(`product:${id}`);
  if (hit) return JSON.parse(hit);
  const product = await db.product.find({ where: { id } });
  await cache.set(`product:${id}`, JSON.stringify(product), { EX: 300 });
  return product;
}
  1. Lines 2 to 3: Check the cache first. A hit returns right away. The database never hears about it.
  2. Line 4: Miss: your code queries the database. The app owns the fallback, so it decides what to load and how.
  3. Line 5: Populate with a TTL. Store the result for the next reader. The TTL bounds staleness if a write path forgets to invalidate.
Check yourself

With cache-aside, the app asked the cache for product:42 and missed. It has just read the product from the database.

What does the app do next?

  • Returns the product and leaves the cache empty
  • Writes the product into the cache, then returns it
  • Waits for the cache to fetch it from the database
  • Asks the database to push it into the cache
Show the answer
  1. Writes the product into the cache, then returns it

In cache-aside the application does all the work: check the cache, read the database on a miss, then fill the cache (usually with a TTL) so the next read hits. The cache knows nothing about the database.

Cache-aside: the app checks, reads the source on a miss, and fills the cache itself.

Read-through: the cache does the fetching

With read-through, the app only ever talks to the cache. On a miss, the cache calls the loader you registered, stores the result and returns it. Same data flow, but the miss logic lives in one place.

Side by side

Cache-aside

app loads

On a miss
Your code queries the DB
Cache down
Reads fall back to the DB
Works with
Any key-value cache

Read-through

cache loads

On a miss
The cache calls its loader
Cache down
Reads fail without a fallback
Works with
Caches that support loaders
Check yourself

Which statements are true of cache-aside?

  • The application queries the database on a miss
  • The cache calls a registered loader on a miss
  • If the cache is down, reads can fall back to the database
  • Every write updates the cache and the database together
Show the answer
  1. The application queries the database on a miss
  2. If the cache is down, reads can fall back to the database

In cache-aside the cache is a plain key-value store next to your code. Your code handles misses, so it can also route around a cache that's down. A cache that calls a loader is read-through, and updating both stores on every write is write-through.

Cache-aside: your code owns the miss path, so it can route around a dead cache.

Recall

With read-through, who fetches the value on a miss, and what does the application gain?

Show the answer

The cache does, through a loader it was configured with. The application only ever asks the cache, so the fetch-and-fill logic lives in one place instead of every caller.

Recap

  • Cache-aside: your code checks the cache, loads from the database on a miss and populates the cache.
  • Read-through: the cache calls a loader on a miss; the app only talks to the cache.
  • Cache-aside degrades gracefully when the cache is down. Neither pattern handles writes for you.

Start with one byte

Join the waitlist and get the beta invite when it opens.

  1. Bit1U
  2. Nibble2U
  3. Byte4U
  4. Kilobyte8U
One unit more at every level