~learn.

Caching, on one page.

Prints on a single A4 or Letter page. Download PDF opens your browser's print dialog: choose “Save as PDF”.

System Design Mastery · World 04 cheat sheet

Caching

~/himanshufree course · himanshukukreja.in/learn

Day 1Caching Patterns

Why cache. Latency (database 10–100 ms, Redis 0.5–2 ms, local memory 0.0001 ms), throughput (5,000 database queries/s vs 100,000+ Redis ops/s) and cost. "Just add Redis" isn't a strategy.

Cache-aside is the default. The app checks the cache, on a miss reads the database and fills the cache, and on writes invalidates the key. Only used data gets cached, and a cache outage just makes things slower.

Write-through vs write-behind. Write-through updates cache and database together: fresh reads, slower writes, for balances and inventory. Write-behind acks after the cache and flushes later in batches: fastest, but a cache crash loses data.

Mix patterns per data type. In one store: catalog cache-aside, inventory write-through (or no cache during a sale), prices cache-aside with event-driven invalidation, view counts write-behind. Checkout always reads the database.

TTL is the safety net. Invalidation can fail on a Redis timeout. A TTL sized to the staleness you can accept means a stale value still expires: product details 1 hour, prices 5 minutes, inventory 30 seconds.

10,000 × 5 = 50,000queries/s on a database built for 5,000: the outage
99% → 0%hit ratio after a restart: 10 → 1,000 req/s reach the database
> 95%hit ratio target; alert below 80–90%
80%of maxmemory: alert before evictions spike
Trade-off · The four caching patterns
Write latencyConsistencyData loss risk
Cache-asideDatabaseEventualLow
Read-throughDatabaseEventualLow
Write-throughCache + databaseFresh after writesLow
Write-behindCache onlyEventualHigh
  • Letting a cache error become a 500 instead of falling back to the database.
  • Caching everything: rarely read data evicts the hot set and lowers the hit ratio.
  • Collision-prone keys like user; use product:{id}:v1 with a schema version.

Day 2Invalidation Strategies

The cache doesn't know the data changed. A flash sale moved a price from $99 to $79, but the 1-hour TTL kept showing $99 and 147 customers complained. Match each data type's invalidation to its staleness tolerance.

TTL, events, versions. TTL: simple, stale until expiry. Event-driven: publish on change and delete the key in ~100–500 ms, but needs Kafka and a DLQ. Versioned keys: bump product:123:v5 to v6, or a global version to invalidate everything.

Delete, don't update. Write-update races: two writers can leave the cache holding the older value. Deleting is idempotent and the next read loads fresh data; update in place only with one writer or atomic ops like INCR.

Invalidate after commit. Deleting inside the transaction lets a reader cache the old row before commit, leaving cache and database apart indefinitely. Facebook's leases go further: a fill after an invalidation is refused.

Decompose the cache. Cache product:123:details (24 h), price (5 min plus events), inventory (30 s plus events) and reviews (1 h) separately, so an inventory change doesn't evict the description.

TTL = staleness × 0.8e.g. 5 minutes tolerated → 4-minute TTL
~100–500 msevent-driven invalidation latency
99% · 1%invalidations handled by events vs by the TTL safety net
< 30 s · < 5 minstaleness tolerance: inventory, prices
Trade-off · Invalidation strategies
FreshnessComplexityUse for
TTL onlyMinutesLowStatic, tolerant reads
Event-drivenSecondsHighPrices, inventory
Versioned keysSecondsMediumBulk updates, deploys
TTL + eventsSecondsMedium-highMost systems
  • Invalidating only product:123 and forgetting category pages, search results and deals.
  • Pattern deletes (KEYS category:*) in the hot path; track keys per category in a set.
  • Event-driven invalidation with no TTL: one lost event means stale forever.

Day 3Thundering Herd

One expiring key can take the site down. When a hot key expires, every concurrent request misses and queries the database: 1 miss becomes N queries. 50,000 homepage requests met a database built for 5,000 queries a second.

Coalesce misses into one fetch. Request coalescing (single flight) lets concurrent requests for a missing key join one in-flight fetch and share its result. Instagram caches a promise for the value; locking does the same with more waiting.

Never let hot keys expire. Background refresh recomputes known hot keys (homepage, trending, deals) before their TTL, so users never miss. For a scheduled change, pre-warm the new key and switch atomically.

Serve stale while revalidating. When an entry goes stale, return it immediately and refresh in the background. If the refresh fails, extend the stale window instead of letting it lapse onto a struggling database.

Desynchronize expiry. Jitter TTLs and refresh probabilistically just before expiry, weighted by how long recomputing takes, so keys loaded together don't all expire together.

10 s · 5 slock TTL; how long a waiter waits before fetching itself
> 10K/s per keyprefer coalescing; locking for moderate traffic
90 s TTL · 60 s refreshtrending cache: 30 s of buffer
Trade-off · Thundering herd defenses
Latency costComplexityBest for
LockingHigh: waiters blockLowModerate traffic
CoalescingLowMediumHigh traffic
Probabilistic expiryNoneLowMany keys, distributed
Background refreshNoneHighKnown hot keys
Stale-while-revalidateNoneMediumStale is fine
  • One TTL for everything, so the homepage expiring sends 10K queries at once.
  • Coalesced waiters with no timeout; fall back to stale data instead.
  • Deploying with a cold cache; warm hot keys behind a health-check gate first.

Day 4Feed Caching

Reads vs writes pull apart. Computing a feed on read means querying every followee (500 × 10 ms = 5 s). Precomputing it means every post fans out to every follower: one celebrity post is 50 million cache writes.

Fan-out on write. When a user posts, push the post ID into each follower's feed cache (a Redis sorted set scored by time). Reads become one cache lookup; the cost moves to writes and storage.

Hybrid push and pull. Push posts from regular users (under ~10K followers); store celebrity posts once and pull them at read time, merging with the precomputed feed. Twitter and Instagram run mostly push.

Cache IDs, trim, skip the dormant. Store post IDs, not posts, and trim each feed (~800 entries). Skip long-inactive followers during fan-out and rebuild their feed when they return; fetch pulled posts in parallel.

100M × 50 KB = 5 TBcaching full feeds instead of IDs
~1.1M/sfeed insertions: 500M tweets/day × 200 followers
50 minto push 300M writes at 100K/s: why celebrities are pulled
< 200 msfeed latency target
Trade-off · Fan-out on write vs on read
On write (push)On read (pull)
Read latencyOne cache readN queries
Write costN cache writesOne write
StorageA feed per userPosts only
Best forRegular usersCelebrities, 2nd-degree feeds
  • Pure push for everyone: one celebrity post backs up the fan-out for an hour.
  • Feeds never trimmed, so sorted sets grow forever.
  • Fetching each followee's posts sequentially instead of in parallel.

Day 5Multi-Tier Caching

Five layers, five jobs. Browser (static assets, preferences), CDN (public content, media), API gateway (auth validation, rate limits, dedup), Redis (business data, sessions, flags), database buffer pool (automatic).

Invalidate closest to the database first. Delete the Redis key, then the gateway cache, then purge the CDN asynchronously. Purge the CDN first and it may refetch the old value from a still-stale origin cache. Browsers expire only by TTL.

Never let the CDN cache personal data. Mark authenticated responses Cache-Control: private. Vary on headers that change the content (Accept-Language, Accept-Encoding), never on Cookie: that gives every user their own cache entry.

Bounded staleness, not perfect consistency. Design a maximum staleness per tier: CDN 60 s, Redis 5 minutes (usually seconds with events), browser 60 s for API data. Checkout bypasses every cache.

20 · 5 · 2 · 50 msCDN, gateway, Redis, disk; browser 0
1 year, immutablehashed JS/CSS; HTML gets no-cache with an ETag
> 95%CDN hit ratio target for static assets
95%of Netflix's bandwidth is video on the CDN
Trade-off · Anonymous vs authenticated requests
AnonymousAuthenticated
CDNCache aggressivelyDon't cache personal data
GatewayCache API responsesAuth checks, rate limits
App cacheShared dataPer-user data
  • An authenticated /api/profile cached at the CDN: one user's data served to another.
  • Missing Vary: Accept-Language, so Spanish users get the English page.
  • Unversioned keys: a deploy reads the old schema; put v3 in the key.

BossDesign a Global E-Commerce Product Catalog System

At 600K req/s, the hit rate is the design. 500M daily views is ~6,000 req/s, and flash sales spike it 100x. Even 1% misses at 600,000 req/s means 6,000 database queries a second: hit rate must exceed 99%.

Freshness per data type. Metadata tolerates an hour (TTL), prices under 5 seconds (events plus a 30 s TTL), inventory under 30 seconds for display, and checkout reads live data. Images can be a week old.

Flash sale protection. Pre-warm the deal before midnight, coalesce concurrent misses into one fetch, refresh hot keys in the background and serve stale while revalidating. Last Black Friday a single expiring key took the site down.

Personalization by activity tier. Precompute recently viewed and recommendations for active users, give recent users shorter TTLs, compute on demand for dormant ones. Caching all 100M users' 3.5 KB would waste most of 350 GB.

Degrade when Redis fails. A circuit breaker detects the failure in under a second; serve stale data from a local in-process cache, hide personalization, pause flash-sale purchases to avoid overselling, then recover half-open after 30 seconds.

~300 GBRedis: 80 products, 200 personalization, 10 categories
< 50 ms · < 200 mspage latency on a cache hit vs a miss
10%of all traffic goes to Deal of the Day
Trade-off · Where each piece is cached
BrowserCDNRedis
Static assets1 year1 yearNo
Anonymous page60 s, swr 30 s60 s5 min, events
Price, inventoryNoNo30 s, events
CheckoutNoNoNo
  • Letting the Deal of the Day key expire at midnight instead of pre-warming it.
  • Caching prices at the CDN: checkout then disagrees with the page.
  • Precomputing personalization for every registered user, active or not.