Kazi Rahamatullah
Kazi Rahamatullah
AboutProjectsBlogContact
UsesBooks
ResumeView CV
Kazi Rahamatullah

© Copyright 2026 Kazi Rahamatullah

AboutProjectsBlogBooksUses
Twitter/XGitHubProduct HuntCodeSandbox
Back to Blog
System DesignCachingRedisCDNPerformance

System Design: Caching Strategy

Where to cache, how to invalidate, and consistency trade-offs — with an interactive simulator for hit ratio, latency, and multi-layer caching.

Jul 8, 20262 min read

Introduction

Quote

Do not cache everywhere — cache in the right place.

Caching is not a default — it is a deliberate trade-off between speed, freshness, and complexity. Cache hit ratio, invalidation logic, and consistency boundaries are what separate a fast system from a stale one.

← Back to System Design overview

When to cache

Data typeCache?Why
Product catalogYes (CDN + Redis)Read-heavy, tolerates short staleness
User sessionYes (Redis)Fast lookup, TTL-based expiry
Account balanceCarefulStrong consistency often required
Search resultsSometimesShort TTL, invalidate on write

Warning

Never cache personalized or authorized data at a shared CDN edge without validating cache keys per user or using private cache headers.

Cache layers

plaintext
Client → CDN → Load Balancer → API → Redis → Database

Each layer has a different TTL and invalidation strategy:

  1. CDN — static assets, public GET responses
  2. Application cache (Redis) — computed aggregates, session, rate-limit counters
  3. Database query cache — often replaced by Redis in modern stacks

Interactive simulator

Pick a strategy and simulate requests. Watch hit ratio and latency change.

Cache Strategy Simulator

Not every layer needs a cache — pick the right one and measure hit ratio.

Hit ratio

78%

Avg latency

48ms

Cache hits

0

Hot keys stored in memory with TTL invalidation.

Path: Client → API → Redis → Database · Misses: 0

Invalidation strategies

TTL (time-to-live)

Simplest: data expires after N seconds. Good for catalog pages where 30–60s staleness is acceptable.

Write-through / write-behind

Update cache when the database writes. Keeps cache warm but adds write latency.

Cache-aside

App reads cache → on miss, read DB → populate cache. Most common pattern:

typescript
async function getProduct(id: string) {
  const cached = await redis.get(`product:${id}`)
  if (cached) return JSON.parse(cached)
 
  const product = await db.products.findById(id)
  await redis.set(`product:${id}`, JSON.stringify(product), 'EX', 300)
  return product
}

Consistency trade-offs

ModelBehaviorUse when
StrongAlways freshPayments, inventory locks
EventualMay be stale brieflyFeeds, analytics, catalog
Read-your-writesUser sees own updatesProfile, settings

Interview Answer

Caching answer structure: identify read-heavy paths → pick layer (CDN vs Redis) → state TTL → explain invalidation on write → mention stampede protection (single-flight lock) for hot keys.

Back to index


Share this article

XLinkedInFacebook
Kazi Rahamatullah

Written by

Kazi Rahamatullah

FullStack Developer

X / TwitterGitHubLinkedIn

Subscribe to my newsletter

Stay up to date and get notified when I share new contents.

No spam ever, unsubscribe anytime