What is CDN
A CDN cuts latency by moving copies of your content onto caching servers physically close to users, so the byte a user needs travels ~5 ms across the city instead of ~200 ms across an ocean — and once one user pulls an object through an edge, every later user in that region is served from local RAM/SSD without the request ever reaching your origin.
The mechanism, end to end
Two things happen on every request. First, anycast routing (or DNS steering) sends the user's TCP/TLS connection to the topologically nearest Point of Presence (PoP) — the same destination IP is announced from hundreds of locations, and BGP delivers the packets to the closest one. Second, the edge server computes a cache key (normally method + host + path, and sometimes selected query params or Vary headers) and looks it up:
- HIT — a fresh copy exists (age < TTL): serve it from the edge in one round trip. The origin never sees the request.
- MISS — no copy, or the copy is stale (age > TTL): the edge opens a connection to origin, fetches the object, stores it keyed by that cache key with the TTL from
Cache-Control: max-age, and streams it to the user.
The whole value of a CDN is a high HIT ratio: the fraction of requests answered without touching origin. Everything else — TTLs, purge, cache keys, Vary — exists to push that ratio up while keeping content fresh.
Worked trace: 500 KB hero image, TTL 3600 s
User in Mumbai, origin in us-east-1 (Virginia). Mumbai↔Virginia RTT ≈ 210 ms; user↔Mumbai-PoP RTT ≈ 5 ms. TCP + TLS costs roughly two round trips before the first byte.
| Step | Request 1 (cold, MISS) | Request 2 (warm, HIT — same client, connection kept alive) |
|---|---|---|
| Route to nearest PoP (anycast) | 5 ms | 5 ms |
| TCP + TLS to edge (~2 RTT) | ~15 ms | 0 (connection reused) |
| Edge cache lookup | MISS | HIT (age 40 s < 3600 s) |
| Edge → origin fetch (2 RTT + transfer of 500 KB) | ~450 ms | skipped |
| Edge stores object + streams to user | ~10 ms | ~15 ms serve from SSD |
| User-perceived latency | ≈ 480 ms | ≈ 20 ms |
| Origin load | 1 request | 0 requests |
Note the warm column assumes the same client on a kept-alive connection; a new user hitting the warm edge pays their own ~10 ms handshake (2 RTT to the PoP) — still ~30 ms, not 480 ms. The shared win is the cache fill; the private win is the kept-alive connection. Across a realistic mix — say a 95% hit ratio on this object — the effective average latency is 0.95 × 20 + 0.05 × 480 ≈ 43 ms (assuming warm connections), versus ~480 ms with no CDN, and only 5% of requests ever reach the origin. That ~11× effective speedup (24× on every hit) and 95% offload is the entire pitch, and it evaporates the moment your hit ratio collapses — which is exactly what the pitfalls below cause.
Pitfalls a working engineer hits
- Caching a personalized response. If origin returns user-specific HTML/JSON but forgets
Cache-Control: private(or the CDN is configured to ignoreSet-Cookie), the edge caches user A's dashboard and serves it to user B under the same cache key. This is a real data-leak incident class, not a hypothetical. Rule: authenticated/personalized responses must beprivateorno-store, or keyed on the identity. - Query strings shattering the cache key. Marketing appends
?utm_source=…&fbclid=…. If the CDN keys on the full query string,/logo.png?utm=aand/logo.png?utm=bare two distinct objects — one hot image becomes thousands of cold misses and your hit ratio craters. Strip or allow-list query params in the cache key. - Cache stampede / thundering herd. A popular object's TTL expires; in the next second 10,000 users MISS simultaneously and the edge fires 10,000 concurrent fetches at origin, which falls over. Mitigate with request coalescing (single-flight to origin) and
stale-while-revalidate. - Purge is not instant. Invalidating an object propagates across PoPs over seconds to minutes; users on unpurged edges see stale content. For correctness-critical updates, prefer versioned URLs (
app.a1b2c3.js) over purging. - The
Varytrap.Vary: User-Agentforks the cache into thousands of variants (one per UA string) and destroys the hit ratio;Vary: Accept-Encodingis fine. ForgettingVaryentirely can serve a gzipped body to a client that can't decode it. - Silent no-cache from origin. A framework default sends
Cache-Control: no-storeand everything becomes a MISS — the CDN dutifully proxies at full origin latency and you wonder why it 'isn't working'. Always verify theX-Cache: HIT/MISS(orcf-cache-status/age) header, don't assume.
When to use a CDN — and when not to
Reach for a CDN when you serve a geographically dispersed audience, a large share of your bytes are cacheable (static assets, images, video, versioned bundles, or public API responses), you face traffic spikes, or you need edge DDoS/TLS termination. The signal is simple: high read-to-write ratio on content many users share.
Trade-offs versus the alternatives:
- vs. a single origin with good
Cache-Controlheaders + browser cache. The browser cache is free and gives 0 ms on repeat visits, but it's per-user and empty on the first visit and for every new user. A CDN warms across users. Choose plain browser caching for a low-traffic, single-region app where a CDN's fixed cost and added moving parts aren't worth it; add a CDN once first-visit latency or origin load bites. - vs. a reverse-proxy cache in front of origin (nginx/Varnish). A local reverse proxy offloads origin CPU and gives you a shared cache, but it lives in one region — it does nothing for the 210 ms of physics between Mumbai and Virginia. Choose the reverse proxy when your users are near origin and the goal is origin offload; choose a CDN when geography is the latency, not compute.
- vs. multi-region origin replicas. Replicas serve dynamic, personalized content close to users, which a CDN can't cache — but they're far more expensive and complex to run (data replication, consistency). Choose replicas for personalized/write-heavy paths; a CDN only helps the cacheable slice.
What a CDN costs you: an extra layer to debug (which PoP served this? why a MISS?), a freshness/staleness tension you now own (TTL vs. purge), cache-key and header discipline, and egress/request billing. Prefer NOT to CDN highly dynamic, per-user, or write-heavy responses — they can't be shared, so you pay the indirection and get near-zero hit ratio. Choose THIS when content is shared across users and geography is your latency; prefer regional replicas when the hot path is personalized, and prefer a plain reverse proxy when your users already sit next to origin.
Decision table: CDN vs alternatives
| Goal | Best tool | Why |
|---|---|---|
| Repeat-visit latency for static assets | Browser cache | Free, 0 ms on revisit, but per-user only. |
| First-visit latency globally, origin offload | CDN | Shared edge cache close to users. |
| Origin compute offload in one region | Reverse proxy cache | Cheaper than CDN if geography isn't the issue. |
| Dynamic personalized content near users | Multi-region origin / edge compute | CDN cannot cache personalized responses safely. |
| Correctness-critical asset updates | Versioned URLs | Avoids purge propagation delays; cache busts instantly. |
Takeaways
- A CDN wins on two axes at once: latency (nearest edge, ~5 ms vs ~200 ms) and origin offload (a high hit ratio means most requests never reach you). The hit ratio is the number that matters.
- Everything you configure — cache key, TTL,
Vary, purge, versioned URLs — is a lever on the freshness-vs-hit-ratio trade-off. Cache-key hygiene and query-param stripping protect the hit ratio; versioned URLs beat purging for correctness. - Cache only what is safe to share: personalized/authenticated responses must be
private/no-store, or you leak one user's data to another. - A CDN helps the cacheable slice of traffic only — dynamic personalized content needs replicas or edge compute, not a cache.
L0 · A CDN caches copies of content at edge PoPs near users — HITs serve locally, MISSes forward to origin, trading a small freshness lag for large latency and origin-offload wins.
L1 · ① Concurrency — "TTL on a viral hot object just expired — what happens next?"
Trap: "Edge just gets a MISS and quietly refetches from origin, no big deal."
Bar: At expiry, hundreds of near-simultaneous requests can hit the same edge in that same second — without coalescing, each fires its own origin fetch, a self-inflicted thundering herd. Production edges do single-flight: the first MISS locks the cache key, later requests wait on that one in-flight fetch, and stale-while-revalidate lets everyone else keep getting the old copy instead of blocking. connects-to: cache stampede — single-flight, soft TTL, dedup
L2 · ② Failure — "Origin returns 500 (or times out) on a MISS — what does the user see?"
Trap: "The CDN is just a proxy, so it faithfully passes the 500 through to the user."
Bar: That's exactly what happens if stale-if-error isn't configured. With it set, the edge instead serves the last known-good cached object past its TTL, bounded by a max-stale window, turning an origin outage into a slightly-stale-but-live response instead of a hard failure. connects-to: CDN serve-stale on origin error
L3 · ③ Scale — "You run 300 PoPs worldwide and this object just got purged everywhere — next traffic spike, what happens?"
Trap: "Each PoP independently MISSes and fetches origin — that's the CDN doing its job, fine."
Bar: 300 independent MISSes means up to 300 concurrent origin connections. An origin shield / tiered cache puts one shared parent cache between edges and origin per region, so those 300 edge MISSes collapse into a handful of shield-tier fetches — origin sees single digits, not hundreds. connects-to: CDN architecture — origin shield, tiers
L4 · ④ Time/Lifecycle — "You just purged a cached asset with a wrong price baked in — is it gone from every PoP now?"
Trap: "Purge is a global instant delete — once the API returns 200, the object is gone everywhere."
Bar: Purge is an async fan-out to hundreds of PoPs; propagation is typically seconds but can run to minutes, so a PoP that hasn't received it yet keeps serving the stale object from its own local cache. For correctness-critical changes, ship a new versioned URL instead — that forces a cache miss everywhere immediately, with no propagation window to wait out. connects-to: cache invalidation
L5 · ⑤ Adversary/Edge — "An attacker sends X-Forwarded-Host: evil.com — that header isn't in your cache key, but origin reflects it into the page. What breaks?"
Trap: "Doesn't matter — the cache key is just method+host+path, so the attacker's request stays isolated to its own entry."
Bar: The poisoned response gets stored under the victim's normal cache key, precisely because the header was unkeyed — every legitimate user hitting that same URL now gets the attacker's injected payload until TTL expiry or purge. The fix is keying on that header explicitly or stripping/normalizing it at the edge before it ever reaches origin. connects-to: CDN cache poisoning via unkeyed headers
The floor keeps dropping: now compound it — a whole-CDN-provider outage forces multi-CDN DNS failover, but the second vendor's cache-key/Vary semantics differ from the first, and an auth cookie riding along unkeyed leaks one user's personalized response to another across both vendors at once. Is running two CDNs worth that operational and cost overhead versus just eating one provider's SLA-covered downtime?
Self-locate: died at L1 → mid-level; L4+ → staff signal.
Facing any new concept? Hit it with the six: concurrent? failing? at 100×? over time? adversarial? worth the cost? — that's the interviewer's whole playbook.
Sources: MDN Web Docs on HTTP caching (Cache-Control, Vary, stale-while-revalidate); Cloudflare and Fastly Learning Center articles on how CDNs, cache keys, anycast, and purging work; Google SRE Book (cache stampede / request coalescing); and RFC 9111 (HTTP Caching). Latency figures are representative order-of-magnitude values for a Mumbai↔us-east-1 path. Re-authored/Deepened for this guide.
🤖 Don't fully get this? Learn it with Claude
Stuck on What is CDN? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **What is CDN** (System Design) and want to truly understand it. Explain What is CDN from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **What is CDN** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **What is CDN** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **What is CDN** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.