Caching

Store the result of expensive work close to where it’s needed. The highest-leverage performance and cost lever — and a top source of subtle bugs (staleness, stampedes).

Where Caches Live

  • Client / browser — HTTP caching (Cache-Control, ETag).
  • CDN / edge — static assets and cacheable responses near users.
  • Application — in-process (LRU, see LRU Cache) or distributed (Redis, Memcached, AWS ElastiCache / DynamoDB DAX).
  • Database — query/result and buffer caches.

Read Patterns

  • Cache-aside (lazy loading) — app checks cache; on miss, loads from DB and populates. Most common. Risk: stale data, and a cold cache means a DB stampede.
  • Read-through — the cache loads from the DB itself on miss (library/provider does it).

Write Patterns

  • Write-through — write to cache and DB together. Consistent, slower writes.
  • Write-behind (write-back) — write to cache, flush to DB async. Fast, risk of loss on crash.
  • Write-around — write straight to DB, populate cache on next read. Good for write-heavy, read-rare data.

Invalidation

“There are only two hard things in computer science: cache invalidation and naming things.”

  • TTL / expiry — simplest; accept bounded staleness.
  • Explicit invalidation / event-driven — bust on write (via Messaging & Event-Driven Architecture).
  • Versioned keys — change the key on update; old entries age out.

Failure Modes

  • Stampede / thundering herd — many misses hit the DB at once on expiry. Mitigate with request coalescing, jittered TTLs, or pre-warming.
  • Hot keys — one key dominates traffic; shard or replicate it.
  • Stale reads — pick a staleness budget per dataset; don’t cache what must be strongly consistent.

Eviction Policies

LRU (default mental model), LFU, FIFO, TTL-based. Size the cache to your working set, not your dataset.