Skip to main content

CDN & Caching Across Layers

Level 1: Level 1: Foundations & Mental Modelsmedium30 mincdncachinginvalidation

Cache as high up the browser-CDN-app-Redis stack as possible, default to cache-aside, mix TTL/purge/event invalidation, and never let a shared cache hold user data.

The highest-leverage tool, and the nastiest bugs

Caching is the highest-leverage performance tool you have: it turns a 50 ms database query into a sub-millisecond memory hit and takes load off the systems that are hardest to scale. It is also the source of the nastiest correctness bugs, because a cache is a copy of the truth that can silently go stale. Phil Karlton's line ("there are only two hard things in computer science: cache invalidation and naming things") is a joke that ships incidents.

Think of caching as a stack of layers, each catching what the layer above missed:

Browser cache (private, per user)
   |
CDN / edge POP (shared, geographic)
   |
Reverse proxy / gateway cache
   |
App in-memory cache (local, per instance)
   |
Distributed cache (Redis / Memcached, shared)
   |
Database buffer pool (pages in RAM)

The closer to the user a request is served, the cheaper and faster it is, so you try to satisfy reads as high up as possible. A product page image should be served from the browser or CDN, never from your database.

Write/read policies

  • Cache-aside (lazy loading) is the default. The app checks the cache; on a miss it reads the DB, writes the value into the cache, and returns it. Simple and resilient (a cache outage just means slower reads), but the first read after a write is a miss, and you must invalidate on writes or serve stale data.
  • Read-through is cache-aside where the cache library, not your code, loads from the DB on a miss. Same semantics, less boilerplate.
  • Write-through writes to the cache and the DB together on every write, so the cache is always fresh, at the cost of write latency and caching data that may never be read.
  • Write-behind (write-back) writes to the cache immediately and flushes to the DB asynchronously. Fast writes, but you risk data loss if the cache dies before the flush.
Check yourself

Four policies just went by. Match each observed behavior to the policy that produces it.

A cache outage means slower reads, not wrong answers
Writes pay extra latency, but reads never see stale data
Writes are fast, but a cache crash can lose acknowledged data
The first read after a write misses unless you invalidate

Invalidation, the hard part

Three strategies, usually combined. TTL expires entries after N seconds; simple and self-healing, but you serve stale data for up to the TTL, so you tune TTL against how stale you can tolerate. Explicit purge deletes or updates the entry when the underlying data changes; precise but requires the write path to know every cache key it affects. Event-driven invalidation publishes a change event (via Kafka or a CDC stream) that fan-out invalidates caches; this scales to many caches but is more machinery. A powerful pattern is stale-while-revalidate: serve the stale value immediately while asynchronously refreshing it, which hides refresh latency and keeps you serving during a backend blip. Guard hot keys against a cache stampede (thundering herd): when a popular key expires and a thousand requests all miss and hit the DB at once, use request coalescing (single-flight), a short lock, or jittered TTLs so they do not all expire together.

The CDN

The CDN is the caching layer nearest the user: a network of anycast POPs worldwide that cache your static (and cacheable dynamic) content near users, cutting latency and offloading your origin. Key knobs: the cache key (usually URL plus a chosen subset of headers/query params; include too much and hit rate collapses, include user-specific fields and you leak data), Cache-Control headers (max-age, s-maxage for shared caches, immutable for content that never changes), and cache busting. The clean way to invalidate a CDN asset is not to purge, it is to version the URL: ship app.9f3a1c.js (a content fingerprint) with a one-year immutable TTL, and when the file changes the filename changes, so clients fetch the new URL and the old one just ages out. Purge APIs exist for emergencies, but fingerprinting avoids the need.

Check yourself
You put the CDN in front of everything, and 'GET /account', each user's own dashboard, gets cached with 's-maxage=300' like any other page. What is the failure?

Interview nuance: The correctness landmine is caching personalized or authenticated responses. Never let a shared cache (CDN or proxy) store a response that contains one user's data, or you will serve Alice's account page to Bob. Mark those Cache-Control: private, no-store, and be careful with the Vary header: Vary: Cookie technically keys per user but destroys hit rate, so the right move is usually to not cache authenticated responses at the shared layer at all and cache only truly public assets.

Recap: Cache as high up the browser-CDN-proxy-app-Redis-DB stack as you can, default to cache-aside, invalidate with a mix of TTL, explicit purge, and events plus stale-while-revalidate, version CDN URLs instead of purging, defend hot keys against stampedes, and never let a shared cache store authenticated responses.

Check yourself
Your logo file shipped with a rendering bug. It is cached at the CDN under '/static/logo.png' with a one-year 'max-age'. What is the cleanest fix?

Apply

Your turn

The task this lesson builds to.

Design the caching layers for a read-heavy product page and state your invalidation strategy at each layer, including the CDN.

Think about

  1. What are the cache layers from browser to DB buffer?
  2. Which write policy (cache-aside, write-through, write-back) fits, and how do you invalidate?
  3. How do you invalidate a stale CDN asset?

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Design the caching and invalidation strategy for a news homepage like the BBC during a breaking-news event, where a single URL gets 500k requests per second globally and an editor's correction to the headline must reach every reader within about 10 seconds without melting the origin. Explain your CDN strategy, invalidation, and stampede protection.

Think about

  1. What fraction of 500k RPS can the origin afford to see, and what keeps the rest at the edge?
  2. Why is TTL expiry alone not enough for a 10-second correction target?
  3. What stops thousands of edge misses from stampeding the origin when the entry expires?