Skip to content

Caching Strategies#

Problem statement (interviewer prompt)

Walk through the four canonical cache patterns (cache-aside, read-through, write-through, write-back) for a read-heavy product. Explain when to use each, how to size the cache, and how to handle stampedes, hot keys, and invalidation across multiple servers.

Redis logo, the in-memory data store most commonly used as a cache
Redis logo, © Redis Ltd., via Wikimedia Commons.
flowchart LR
  C([Client])
  A[App]
  K[(Cache)]
  D[(DB)]
  C --> A
  A -->|1 read| K
  K -. miss .-> A
  A -->|2 load| D
  D --> A
  A -->|3 fill| K
  A --> C

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class C client;
    class A service;
    class K,D datastore;

The four main patterns are cache-aside, read-through, write-through, and write-back.

flowchart TB
  subgraph Tiers[Cache Tiers]
    B[Browser Cache]
    CDN[CDN / Edge Cache]
    REV[Reverse Proxy<br/>Varnish/NGINX]
    APP[App Local<br/>Caffeine/Guava]
    DC[Distributed Cache<br/>Redis/Memcached]
    DBC[DB Buffer Pool]
  end

  subgraph Patterns[Patterns]
    CA[Cache-Aside<br/>look-aside]
    RT[Read-Through]
    WT[Write-Through]
    WB[Write-Back<br/>write-behind]
    WA[Write-Around]
    REF[Refresh-Ahead]
  end

  subgraph Eviction[Eviction]
    LRU
    LFU
    TLRU[TTL+LRU]
    ARC
    TwoQ[2Q / TinyLFU]
  end

  subgraph Failures[Failure Modes]
    STAMP[Cache Stampede<br/>thundering herd]
    PEN[Cache Penetration<br/>key never exists]
    AVAL[Cache Avalanche<br/>mass expiry]
    INV[Stale data /<br/>invalidation bugs]
  end

  subgraph Mitigations[Mitigations]
    LOCK[Single-flight /<br/>distributed lock]
    BLOOM[Bloom filter for<br/>missing keys]
    JIT[Jittered TTL]
    NEG[Negative caching]
    VER[Versioned keys]
  end

  Client --> B --> CDN --> REV --> APP --> DC --> DBC
  Client --> Patterns
  Patterns --> Eviction
  Failures --- Mitigations
  STAMP -.->|fix| LOCK
  PEN -.->|fix| BLOOM
  PEN -.->|fix| NEG
  AVAL -.->|fix| JIT
  INV -.->|fix| VER

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class CDN,REV edge;
    class CA,RT,WT,WB,WA,REF,TLRU,STAMP,PEN,AVAL,INV,LOCK,BLOOM,JIT,NEG,VER service;
    class B,APP,DC,DBC,TwoQ cache;

Pattern semantics#

Pattern Read Write Notes
Cache-aside app reads cache, falls back to DB, fills cache app writes DB, invalidates cache most common
Read-through cache transparently loads from DB on miss - cache library does the load
Write-through - app writes cache → cache writes DB synchronously consistent, slower writes
Write-back - app writes cache → cache async-flushes to DB fast writes, durability risk
Write-around - app writes DB, cache filled lazily on read avoids cache pollution by one-time writes
Refresh-ahead proactively refresh hot keys before TTL - predictive

Invalidation#

  • TTL (simplest, drifts).
  • Explicit on write (DEL, pub/sub).
  • Versioned key (user:42:v17) - never invalidate, just bump version.
  • Change-Data-Capture (Debezium) → cache invalidator.

Glossary & fundamentals#

Concepts referenced in this design. Each row links to its canonical page; the tag column shows whether it is a high-level (HLD) or low-level (LLD) concept.

Tag Concept What it is Page
HLD Load balancer / GSLB L4/L7 traffic distribution and failover load-balancer
HLD CDN edge caching for static assets cdn
HLD Cache strategies cache-aside, read/write-through, eviction caching-strategies
HLD Pub/Sub & message brokers topics, consumer groups, delivery semantics pub-sub-pattern
HLD Probabilistic data structures Bloom, HLL, Count-Min, MinHash, t-digest probabilistic-data-structures
HLD Idempotency & retries safe re-execution, backoff + jitter idempotency-retries
HLD Change Data Capture WAL/binlog tailing, outbox publishing change-data-capture
LLD Structural patterns Adapter, Decorator, Facade, Proxy, Composite structural-patterns

Quick reference#

Hierarchy (latency)#

  • L1 CPU cache: 0.5-10 ns
  • RAM: 100 ns
  • App-local (Caffeine): ~µs
  • Remote cache (Redis same DC): 0.3-1 ms
  • SSD: 100 µs
  • HDD: 10 ms
  • Cross-DC: 50-200 ms

When NOT to cache#

  • Mutates frequently and read-immediately-after-write semantics required.
  • Per-user data with tiny re-read probability.
  • Already cheap (< 1 ms) reads.

Sizing#

  • Working-set estimation: 80/20 rule - cache hot 20% to hit 80%.
  • Hit ratio target: 90-99% for read-heavy.

Concurrency pitfalls#

  • Stampede: 1000 RPS hit cache miss simultaneously → all query DB. Fix: single-flight (one fetches, others wait), EX NX lock with backoff, or pre-compute.
  • Inconsistency window: DB updated, cache not yet evicted. Mitigate with short TTL or CDC.

Choosing TTL#

  • Tolerance for staleness × refresh cost.
  • Add jitter (TTL ± 10%) to avoid mass expiry.

Refs#

  • Facebook memcached at scale (NSDI '13), Netflix EVCache, DynamoDB DAX, TinyLFU / W-TinyLFU paper (Caffeine).

FAQ#

What are the four main caching strategies?#

Cache-aside (lazy load), read-through (cache loads on miss), write-through (write to cache and DB synchronously), and write-back (write to cache first, flush to DB async).

What is the difference between cache-aside and read-through?#

In cache-aside the application checks the cache and loads from the DB on miss. In read-through the cache itself loads from the DB on miss, so the app only talks to the cache.

How do you prevent cache stampede?#

Use request coalescing with a single-flight lock, add jitter to TTLs, refresh ahead of expiry, or pre-warm hot keys. Probabilistic early expiration also smooths the renewal pattern.

Write through vs write back, which is safer?#

Write-through is safer because data is durable in the DB before ack. Write-back is faster but risks data loss if the cache crashes before flush. Use write-back only when the DB can rebuild from a log.

When should I use cache-aside?#

Cache-aside is the default for most read-heavy services. It is simple, the cache stays optional, and the app controls what to cache. Use it unless you specifically need write-through consistency.

  • Consistent Hashing: distributed caches use consistent hashing to assign keys to cache nodes
  • CDN: CDNs are a global caching layer built on the same invalidation and eviction principles
  • Database Sharding: caching strategies reduce read pressure on sharded databases

Further reading#

Curated, high-credibility sources for going deeper on this topic.

Video walkthrough

5 Caching Strategies for System Design Interviews : via ByteByteGo