Skip to content
Devgo

Cache-aside

The most common caching pattern: read from cache, on miss load from the DB and populate the cache. The app manages the cache explicitly. Simple and robust, but each miss pays the DB cost plus a write.

When to use
  • Read-heavy workloads with a clear hot set.
  • When you want DB and cache decoupled.
When not to
  • Write-heavy where you'd constantly invalidate.
  • When stale data is unacceptable.

Definition

On a read, check the cache; if absent, query the DB, return the value, and write it to the cache. Writes update the DB and invalidate (or update) the cache. The cache is a side channel, not in the write path.

Why it exists

Most reads hit a small hot set; caching it offloads the DB. Cache-aside is the simplest pattern that works with any cache and any DB, decoupling them.

How it works

GET key → hit returns; miss → SELECT from DB → SET in cache with TTL. On write → UPDATE DB → DEL key (or SET new value). TTLs bound staleness; explicit invalidation on writes keeps it fresher.

Scaling limits

Cache misses are expensive (DB read + cache write). Thundering herd on a cold/expired hot key. Stale data if invalidation is missed. No protection against cache stampede without single-flight or locks.

Cost shape

Cache memory + DB load on misses. Blow-ups: cache churn (low TTL) and stampedes on hot-key expiry.

Alternatives

  • Read-through — Cache transparently loads misses; app doesn't manage it.
  • Write-through — Cache always fresh, but writes pay cache + DB latency.

Failure modes

  • Thundering herd on hot-key expiry.
  • Stale data after a missed invalidation.
  • Cache and DB divergence under failures.

, , , ,