What it is
A content delivery network (CDN) serves content from points of presence (PoPs) close to users, caching what it can so most requests never reach your servers. Four problems define a CDN design: routing (how a user reaches the nearest healthy PoP), the cache hierarchy (what is held where, and what happens on a miss), invalidation (how changed content stops being served), and, for video, segmented delivery (why streaming content caches so well).
Important
Key takeaway: The product is the edge hit ratio. Reach the edge with anycast (fast failover), keep misses off the origin with request coalescing and a regional shield, and make deploys touch zero cached bytes with versioned URLs, reserving purge for the escape hatch.
When you care
“Design a CDN” or “design video streaming” asks for all four. The most common weak answer designs the purge path first and the versioning scheme never.
Note
Interview signal: Describing a miss path with coalescing at both the PoP and a shield (“one origin fetch per object, not one per PoP”) shows you have thought about the origin’s exposure. Saying “I’d version the URLs so a deploy needs no purge” shows you have operated one.
Reaching the edge: routing
| Option | How | Strengths | Flaws |
|---|---|---|---|
| GeoDNS steering | The CDN’s DNS returns a PoP’s address based on the resolver’s location and load | Smart, centralized, tunable per customer | DNS sees the resolver, not the user (a public resolver “locates” a whole country); failover is bounded by TTLs that resolvers ignore, so draining a PoP takes minutes to hours |
| BGP anycast | Every PoP announces the same IP prefix; internet routing delivers to the topologically nearest | Failover is as fast as route withdrawal (seconds); no client cooperation; one IP simplifies certificates | ”Nearest” is BGP’s opinion (hops and peering, not latency); crude load control; a mid-connection route change can move a TCP connection to a PoP without its state |
| Hybrid | Anycast for the data plane, DNS as a coarse tuner of regions and load | Fast failover plus load bias | Complexity |
The usual choice is hybrid, anycast-first: failover agility matters most, and anycast’s load-control gap is patchable with regional DNS maps while DNS’s agility gap is not patchable from the server side. Modern transports (QUIC connection ids) survive path changes, which eases anycast’s mid-connection problem.
The cache hierarchy and the read path

Each tier answers what it can; each miss is coalesced before it goes up.
- The connection lands on the nearest PoP; TLS terminates there (a resumed session saves a round trip, which matters at a 50 ms budget).
- The front end computes the cache key: host, path, and the normalized parts of negotiation (for example
Accept-Encodingcollapsed to a few classes), then consistent-hashes it to the owning cache node in the PoP, so each object lives on about one node and the PoP’s disks add up instead of duplicating. A very hot object is replicated to several nodes. - A RAM hit (the head of the popularity distribution) serves in microseconds, an SSD hit in milliseconds. The response carries correct
Cache-ControlandAgeheaders, so the edge is a conforming HTTP cache and browser caches stack on top for free. - A miss is coalesced: one upstream fetch per object per PoP, with all concurrent requesters waiting on it. The fetch goes to a regional shield, which repeats the same logic before touching the origin.
- The response streams through: first bytes reach the user while the tail is still arriving, and the object is admitted to SSD on the way (or not, by an admission policy that avoids caching one-hit wonders).
Worked example: why a shield earns its hop. A shield adds one regional round trip to a miss, but it removes the origin’s exposure to the PoP count. Without it, an object that expires everywhere at once causes up to 200 simultaneous origin fetches (one per PoP); with one shield per region, only a handful (and with coalescing, one). The shield also concentrates the long tail: an object too cold to stay resident in any single PoP can stay warm in the shared regional cache.
Origin offload arithmetic. At 1,000 requests a second and a 95% edge hit ratio, the origin sees 50 requests a second, a 20× reduction; at 99% it sees 10. Hit ratio is the number to optimize: it depends on cache-key normalization (do not fragment the key on irrelevant headers or query parameters), TTLs, and object size and popularity (a skewed, Zipf-like popularity makes a small RAM tier very effective).
Invalidation
| Scheme | How | Role |
|---|---|---|
| Versioned URLs | The content hash is in the URL (app.9f3ab2.js); the object is immutable and cached with Cache-Control: immutable, max-age=31536000; an update means deploying HTML that points at the new hash | Primary. The consistency problem is deleted, not solved: nothing cached ever needs to change |
| Tagged purge | A control plane fans a purge to every PoP, by surrogate tag (product-123) rather than by URL | The escape hatch: mistakes, takedowns, and mutable URLs you do not control |
Purging by tag beats by URL because one logical change touches many cache keys (variants, encodings), and a tag index makes it one message. To make a “purge within 5 seconds” honest during a network partition, implement purge as an epoch bump, not a deletion: entries record the epoch they were cached under, a purge bumps the tag’s epoch, and a lookup treats an older entry as stale (revalidate before serving). A node that was offline during the purge gets the new epoch with its configuration resync before it takes traffic, so correctness does not depend on the delete racing the reconnect.
Caution
Common mistake: Designing the purge path first and the versioning scheme never. A CDN whose customers purge on every deploy has turned every release into a global-consistency problem across hundreds of PoPs. The right design makes deploys touch zero cached bytes and keeps purge for the rare exception.
Video: why segments cache well
A video is not one big file; it is a manifest listing many short, immutable segments (a few seconds each) at several bitrates. That structure suits a CDN:
- Each segment is a small, immutable, individually cacheable object, so the popular head of the catalog stays at the edge and the cold tail is fetched on demand through the shield.
- Adaptive bitrate (ABR): the player measures its throughput and buffer, and for every segment picks the rendition (resolution and bitrate) it can sustain, switching up or down seamlessly. The same content exists at several quality levels (a bitrate ladder).
- Live streams change the manifest as new segments appear, so the manifest has a very short lifetime while the segments remain immutable.
Warning
Production reality: A cache key that fragments (a session token or tracking parameter in the URL) silently destroys the hit ratio, and a popular object expiring everywhere at once can stampede the origin. Normalize the key, stagger or jitter TTLs, serve stale while revalidating, and watch the hit ratio and the origin request rate as first-class metrics.
When to pick what
| Need | Choose | Why |
|---|---|---|
| Fast failover and one IP | Anycast-first routing, DNS as a coarse tuner | Withdraw a route and traffic shifts in seconds |
| Protect the origin from PoP count | A regional shield with coalescing | One fetch per object, not per PoP |
| Updated assets without purging | Content-hashed versioned URLs, immutable caching | Nothing cached needs to change |
| Remove a bad asset now | Tagged purge via epoch bump | Fast and partition-safe |
| High hit ratio | A normalized cache key and sensible TTLs | The key decides what is shared |
| Video at scale | Immutable segments, ABR ladder, CDN delivery | Cacheable small objects |
Related
- Walkthrough: Designing a CDN — the full CDN design, control plane included.
- Walkthrough: Designing a Video Streaming Platform — segmented delivery and adaptive bitrate on top of a CDN.
- Reference: Cache Access and Invalidation Patterns — the cache-aside and stampede patterns that a CDN applies at the edge.