Skip to main content

Caching

One-line summary: A cache stores copies of expensive-to-fetch data in fast storage so most requests are served in microseconds instead of hitting the database.


๐Ÿงฉ Core Conceptsโ€‹

A cache is a high-speed data layer that stores a subset of data โ€” typically the most frequently or recently accessed โ€” so future requests are served faster. Caching trades a little memory and staleness risk for huge gains in latency, throughput, and reduced load on databases.

Why Cache?โ€‹

  • Reduce latency โ€” memory reads are ~1000ร— faster than disk/DB.
  • Increase throughput โ€” serve more requests with the same backend.
  • Reduce cost & load โ€” fewer expensive DB/API calls, relieving read replicas.

Two key metrics: hit ratio (fraction served from cache) and miss penalty (cost of a miss).


๐Ÿ—๏ธ Cache Layersโ€‹

Caching happens at every tier of a system:

flowchart LR
Client[Client / Browser Cache] --> CDN[CDN Edge Cache]
CDN --> App[Application / In-Memory Cache]
App --> DC[Distributed Cache<br/>Redis / Memcached]
DC --> DB[(Database + Query Cache)]
LayerExampleCaches
ClientBrowser cache, mobile appStatic assets, API responses
CDNCloudflare, CloudFrontImages, CSS/JS, video, edge content
ApplicationLocal in-process, GuavaHot objects near the app
DistributedRedis, MemcachedShared cache across app servers
DatabaseQuery/buffer cacheRecent query results, pages

๐Ÿ”„ Caching Strategiesโ€‹

flowchart TD
R[Read Strategies] --> CA[Cache-Aside]
R --> RT[Read-Through]
W[Write Strategies] --> WT[Write-Through]
W --> WB[Write-Back]
W --> WA[Write-Around]
StrategyHow It WorksProsCons
Cache-Aside (lazy)App checks cache; on miss, loads from DB and populates cacheOnly caches what's used; resilientFirst request is slow; stale risk
Read-ThroughCache library loads from DB on miss automaticallySimple app codeNeeds cache provider support
Write-ThroughWrite to cache and DB synchronouslyCache always freshHigher write latency
Write-Back (write-behind)Write to cache, flush to DB async laterFast writes, absorbs burstsRisk of data loss before flush
Write-AroundWrite straight to DB, bypass cacheAvoids caching write-once dataRecent writes miss the cache

๐Ÿ’ก Cache-aside + write-through is the most common combo for read-heavy web apps.


๐Ÿ—‘๏ธ Eviction Policiesโ€‹

Caches are size-bounded, so they must evict entries when full:

PolicyEvictsBest For
LRU (Least Recently Used)The item unused for the longest timeGeneral-purpose; temporal locality
LFU (Least Frequently Used)The least-accessed itemStable popularity distributions
FIFO (First In, First Out)The oldest inserted itemSimple, order-based workloads

๐Ÿ”— See a full, worked LRU cache implementation here: LRU Cache.


โณ TTL (Time-To-Live)โ€‹

A TTL sets an expiry on each entry so stale data auto-evicts:

  • Short TTL โ†’ fresher data, lower hit ratio.
  • Long TTL โ†’ higher hit ratio, more staleness.
  • Add jitter to TTLs so many keys don't expire simultaneously (avoids thundering herd).

๐Ÿชฒ Cache Invalidationโ€‹

"There are only two hard things in Computer Science: cache invalidation and naming things."

Keeping the cache in sync with the source of truth:

  • TTL / expiry โ€” let entries age out (simplest, eventually consistent).
  • Write-through / write invalidation โ€” update or delete the cache key on every write.
  • Event-based โ€” publish change events (e.g., via message queues) to invalidate keys.
  • Versioned keys โ€” embed a version/hash in the key so new data uses a new key.

๐Ÿ’ฅ Thundering Herdโ€‹

When a popular key expires (or the cache restarts), many concurrent requests miss at once and stampede the database.

flowchart TD
K[Hot key expires] --> M[1000s of misses]
M --> DB[(Database overload)]

Mitigations:

  • Request coalescing / locking โ€” only one request recomputes; others wait.
  • Stale-while-revalidate โ€” serve stale data while refreshing in the background.
  • TTL jitter โ€” spread expirations over time.
  • Cache warming โ€” pre-populate hot keys before traffic.

๐ŸŒ Distributed Cachesโ€‹

When one machine's memory isn't enough or the cache must be shared across app servers, use a distributed cache:

RedisMemcached
Data typesRich (strings, hashes, lists, sets, sorted sets)Strings/blobs only
Persistenceโœ… Optional (RDB/AOF)โŒ In-memory only
Replicationโœ… Built-inโŒ (client-side)
Best forComplex data, pub/sub, leaderboardsSimple, high-throughput KV cache

๐Ÿ›ฐ๏ธ CDN (Content Delivery Network)โ€‹

A CDN caches static (and cacheable dynamic) content at edge servers geographically close to users, cutting latency and origin load.

flowchart LR
U1[User US] --> E1[Edge US]
U2[User EU] --> E2[Edge EU]
E1 -->|miss| O[(Origin Server)]
E2 -->|miss| O
  • Great for images, video, CSS/JS, and downloads.
  • Uses TTLs, cache-control headers, and purge APIs for invalidation.

๐Ÿง  Trade-offs / When to Useโ€‹

  • โœ… Use caching for read-heavy, tolerant-to-staleness data with high reuse (hot keys).
  • โŒ Avoid / be careful with rapidly changing data, strong-consistency requirements, or low-reuse data (low hit ratio wastes memory).
  • Every cache adds a consistency vs freshness trade-off โ€” pick strategy, TTL, and invalidation to match your correctness needs (see Consistency Models and CAP Theorem).

Interview Questionsโ€‹

  • How would you design a caching layer for a social feed to balance freshness and latency?
  • Explain cache invalidation strategies and when you'd pick event-based invalidation over TTL-only.
  • How do you mitigate and detect the thundering herd problem at scale?

Production Checklistโ€‹

  • Measure hit ratio, miss penalty, and memory usage per cache instance
  • Add TTL jitter and request coalescing to prevent stampedes
  • Backup critical cached state if persistence is enabled (AOF/RDB in Redis)
  • Monitor eviction rates, CPU, and network latency to the cache cluster

Testing & Monitoringโ€‹

  • Simulate cache restart + expiry events to observe system behavior
  • Load test with realistic access patterns and hot keys
  • Create synthetic traffic to verify cache warming and invalidation flows
  • โœ… Use caching for read-heavy, tolerant-to-staleness data with high reuse (hot keys).
  • โŒ Avoid / be careful with rapidly changing data, strong-consistency requirements, or low-reuse data (low hit ratio wastes memory).
  • Every cache adds a consistency vs freshness trade-off โ€” pick strategy, TTL, and invalidation to match your correctness needs (see Consistency Models and CAP Theorem).

  • LRU Cache โ€” full implementation of the LRU eviction policy
  • Databases โ€” the backing store caches protect
  • Replication โ€” read replicas complement caching
  • Sharding โ€” consistent hashing for distributed caches
  • CAP Theorem โ€” consistency vs availability trade-offs
  • Consistency Models โ€” staleness and consistency guarantees
  • Scalability โ€” caching as a scaling lever

โ† Back to System Design ยท ยฉ sparshjaswal