Stackbook Logo
scalingestablished · low operational burden

Cache-Aside

Also known as: lazy-loading-cache, look-aside-cache

Intent

Let the application load data into a cache on demand, reading the cache first and the database on a miss.

Problem

Database reads dominate load and latency, yet most reads target a small set of hot records. Putting the cache in the data path couples it to the store, while the application already knows what it needs.

Forces

  • •Read-heavy workloads with skewed access
  • •Cache must be allowed to fail without breaking reads
  • •Stale data is acceptable only for bounded time
  • •Only data that is actually requested should occupy memory

Solution

Overview

Cache-aside, also called lazy loading or look-aside, keeps the cache outside the data path. The application owns the logic: read the cache, fall back to the database, and populate the cache itself.

How it works

read(key):
  v = cache.get(key)
  if v is not null: return v
  v = db.query(key)
  cache.set(key, v, ttl=300)
  return v

write(key, value):
  db.update(key, value)
  cache.delete(key)

Writers update the database first and then delete the key. Updating the cache value instead invites a race: two writers can commit to the database in one order and to the cache in the other, leaving the cache wrong until the TTL expires. Deleting makes the next reader load whatever the database holds.

Cache negative results too, with a short TTL, so lookups for missing keys do not hit the database repeatedly. Add jitter to TTLs so keys loaded together do not expire together.

Pitfalls

  • A reader that loaded old data before a write can still set it after the delete. Short TTLs bound the damage; versioned keys or delayed double-delete remove most of it.
  • Treating cache errors as fatal. Wrap cache calls with tight timeouts and fall back to the database.
  • Caching large objects or entire query results that are invalidated by many different writes.
  • A cold start or mass expiry can stampede the database; pair with request coalescing.

Key takeaways

  • Read cache, then database, then populate; on write, update the database and delete the key.
  • Always set TTLs and add jitter.
  • Treat the cache as optional, with timeouts and a database fallback.
  • Measure hit ratio, eviction rate and database load, not just cache latency.

✓ When to Use

  • •Read-heavy data with a hot subset such as profiles or product pages
  • •When the cache may be unavailable and reads must fall back to the database
  • •When different consumers need different cached shapes of the same data

✗ When Not to Use

  • •Write-heavy data that changes faster than it is read
  • •Data needing read-your-writes consistency across all nodes without extra care
  • •Datasets small enough to fit in application memory

Pros

  • +Simple and resilient: cache failure degrades to database reads
  • +Only requested data is cached
  • +Cache and database schemas stay independent

Cons

  • −First read after a miss pays full latency
  • −Stale reads possible between write and invalidation
  • −Every caller must implement the protocol correctly

Cost Profile

Infrastructure

Cache cluster memory

Operational

Low: monitor hit ratio and evictions

Cognitive

Low: well-known protocol

Failure Modes

  • Race between a reader repopulating and a writer invalidating leaves stale data

  • Cache outage sends full traffic to the database

  • Cold cache after restart causes a load spike

Real-World Examples

Alternatives

    Related Patterns

    • caching
    • read-replica

    Competency Domains

    data statereliability ops