design·lab

Real-world combination

Cache-Aside Layer

A cache sitting in front of your store, behind the same interface — hits return instantly, misses load once and populate the cache for next time.

✗ Problem

Every read hits the slow store

A handful of "hot" keys get read constantly — but each read still pays the full cost of a database query or a remote API call, even though the answer barely ever changes.

function getUser(id) {
  // hits the DB every single time —
  // even for the same 5 hot ids, 1000×/sec
  return db.query('SELECT * FROM users WHERE id=?', id);
}
Latency and DB load scale with traffic, not with the size of the hot set. The store becomes the bottleneck for data that rarely changes.
✓ The combination

Front the store with a same-interface cache

A Proxy/Decorator cache sits transparently in front of the store. Read path: check cache → HIT returns fast; MISS loads from the store, populates the cache, then returns. An eviction Strategy (LRU / TTL) bounds memory; writes invalidate.

class CacheAside {
  get(k) {
    let v = cache.get(k);
    if (v !== undefined) return v;  // HIT

    v = store.load(k);           // MISS → slow
    cache.set(k, v, { ttl });    // populate
    return v;
  }
}
Client
Cache
Proxy/Decorator
Store
DB / API
✓ See it live

Read some keys — watch hits, misses and eviction

Cache holds max 3 keys (LRU-ordered). First read of a key is a MISS (goes to the store, slower); reading it again is a HIT (instant). Read a 4th key and the least-recently-used entry is evicted. Tick the clock to expire entries past their TTL.

Client
Cache
max 3, LRU
Store
slow
cache contents (most-recently-used first)
clock: 0 hits: 0 misses: 0

Read a key to begin.

✓ Takeaway

Lazy, bounded, but never free

  • Cache-aside (lazy) reads: the cache is populated on demand, on the first miss — not upfront.
  • Huge latency win for hot data: repeat reads become O(cache) instead of O(store).
  • Bound it: LRU caps memory by size, TTL caps how long an entry may be served.
  • Invalidate on write — update or delete the cached entry, or the client will read stale data.
  • Caution: one of the two genuinely hard problems in computer science — cache invalidation — plus a cold cache means a "thundering herd" of misses right after a restart.
  • Real uses: Redis / Memcached sitting in front of Postgres, MySQL, S3, or a slow upstream API.
🎯 Combines: Proxy/Decorator (transparent front) + Strategy (eviction policy) over the real store.