Skip to main content

Reference: CDN and Edge Delivery

A reference on CDN design — anycast vs GeoDNS routing, PoP and shield caching with request coalescing, versioned URLs vs tagged purge, and video segments.

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

OptionHowStrengthsFlaws
GeoDNS steeringThe CDN’s DNS returns a PoP’s address based on the resolver’s location and loadSmart, centralized, tunable per customerDNS 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 anycastEvery PoP announces the same IP prefix; internet routing delivers to the topologically nearestFailover 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
HybridAnycast for the data plane, DNS as a coarse tuner of regions and loadFast failover plus load biasComplexity

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

The CDN read path: a request lands on the nearest PoP, is hashed by cache key to the owning cache node, served from RAM or SSD on a hit, and on a miss goes to a regional shield with coalescing and then to the origin, with the response streamed back and cached on the way

Each tier answers what it can; each miss is coalesced before it goes up.

  1. The connection lands on the nearest PoP; TLS terminates there (a resumed session saves a round trip, which matters at a 50 ms budget).
  2. The front end computes the cache key: host, path, and the normalized parts of negotiation (for example Accept-Encoding collapsed 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.
  3. A RAM hit (the head of the popularity distribution) serves in microseconds, an SSD hit in milliseconds. The response carries correct Cache-Control and Age headers, so the edge is a conforming HTTP cache and browser caches stack on top for free.
  4. 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.
  5. 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

SchemeHowRole
Versioned URLsThe 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 hashPrimary. The consistency problem is deleted, not solved: nothing cached ever needs to change
Tagged purgeA control plane fans a purge to every PoP, by surrogate tag (product-123) rather than by URLThe 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

NeedChooseWhy
Fast failover and one IPAnycast-first routing, DNS as a coarse tunerWithdraw a route and traffic shifts in seconds
Protect the origin from PoP countA regional shield with coalescingOne fetch per object, not per PoP
Updated assets without purgingContent-hashed versioned URLs, immutable cachingNothing cached needs to change
Remove a bad asset nowTagged purge via epoch bumpFast and partition-safe
High hit ratioA normalized cache key and sensible TTLsThe key decides what is shared
Video at scaleImmutable segments, ABR ladder, CDN deliveryCacheable small objects