The 100 problems, solved / Video and media / 034 · Design a video distribution CDN

Design a video distribution CDN

Edge caches worldwide that serve 80 percent of bytes without touching origin.

Concepts this design leans on

01The design, in the six-step framework

1. Requirements

Functional

  • Serve video segments and manifests for a streaming service from locations close to viewers.
  • Pull content from origin on a miss and keep popular content hot.
  • Let the service purge or re-version an object worldwide.
  • Report per-object and per-region traffic for billing and capacity.
  • Out of scope: transcoding, DRM licence servers, the player.

Non-functional

  • 100 Tbps peak egress worldwide; 200 points of presence.
  • At least 95 percent of bytes served from edge cache; origin sees under 5 Tbps.
  • Time to first byte under 50 ms from an edge within the viewer's metro.
  • No single edge failure visible to viewers; a whole PoP failure adds at most 30 ms.
  • Purge propagates globally within 60 s.
Back of the envelope

100 Tbps ÷ 200 PoPs = 500 Gbps per PoP on average; a large metro PoP handles 2 to 5 Tbps.

A server with two 100 Gbps NICs serves about 150 Gbps of cached bytes, so a 2 Tbps PoP is about 15 servers, each with tens of terabytes of SSD.

The catalogue is hundreds of petabytes, but 90 percent of traffic goes to about 1 percent of objects; a 500 TB cache per PoP holds that head with room for the warm tail.

Origin at 5 Tbps is still large: a regional mid-tier cache in front of origin cuts it further, since many PoPs miss on the same new object at once.

2. Core entities

  • Object: cache key (URL path plus version), size, content type, origin, TTL, immutable flag.
  • PoP: location, servers, capacity, peering, health.
  • Cache entry: object key, server, last access, hit count, stored bytes.
  • Purge: key or prefix, issued_at, propagation state per PoP.
  • Traffic record: object, PoP, bytes, hit or miss, per minute.

3. API

  • GET https://cdn.example/v3/{video}/{rendition}/seg_{n}.m4s: the viewer's player fetches segments; the version is in the path.
  • POST /purge with keys or a prefix; returns a purge id. Called by the video service.
  • POST /prefetch with keys and target regions: warm a launch before it goes live.
  • GET /reports?object=…&from=…: traffic and hit ratio. Called by billing and capacity tools.
  • Internal: edges fetch misses from origin-shield.{region}/…, which fetches from origin.

4. High-level design

ViewersEdge PoPRegionalOriginresolveGET segmentmissmisspurgeaccess logsPlayerAnycast DNS+ steeringPoP load balancer(consistent hashing)Edge cache servers(SSD)Regional shield cacheControl plane(purge, config)Origin(object storage)Traffic logs(stream)

A segment request:

  1. The player resolves the CDN hostname; anycast and DNS steering send it to the nearest healthy PoP based on the resolver's location and current PoP load.
  2. The PoP's load balancer hashes the object key with consistent hashing so that the same segment always lands on the same one or two servers inside the PoP, which keeps each object cached once per PoP instead of on every server.
  3. On a hit the server streams the bytes from SSD, in under 50 ms to first byte.
  4. On a miss the edge fetches from the regional shield cache; the shield coalesces simultaneous misses for the same object into one origin fetch and keeps the object for other PoPs in the region.
  5. The shield fetches from origin on its own miss, and both tiers store the object with its TTL; immutable segments are kept until evicted.
  6. Access logs stream to the traffic pipeline for billing, hit-ratio dashboards and the popularity signal that drives prefetching.

5. Deep dives

How do we reach 95 percent edge hit rate with hundreds of petabytes of content?

The naive cache, least-recently-used across the whole PoP with every server caching whatever it is asked, stores each popular object 15 times and wastes most of the SSD. Hashing requests to a server by key gives one copy per PoP, 15 times the effective cache. Admission is the second lever: a segment requested once by one viewer should not evict a segment ten thousand people will want; the edge admits an object into SSD only on its second request within a window (a tiny Bloom filter remembers first requests), which keeps the one-hit-wonder tail out. Eviction is by size-aware LRU so a 4K segment does not push out twenty 360p segments. With those two, the measured hit rate on real video traffic is in the mid to high 90s because popularity is so concentrated.

What happens when a new episode goes live and ten million players ask for the same segments?

Every PoP misses at once; without protection, 200 PoPs × 15 servers each fetch the same segment from origin, a stampede. Three layers absorb it: within a server, request coalescing makes concurrent requests for one key wait on a single fetch; the shield does the same across the region; and prefetching warms the first segments of a scheduled launch into every PoP before the release time. Origin then sees roughly one fetch per region per segment.

How does a purge reach 200 PoPs in a minute without a broadcast storm?

OptionMechanismTrade-off
Short TTLsObjects expire on their ownLowers hit rate for everything to fix the rare purge
Versioned URLsA re-encode gets a new path; old objects just age outNo purge needed for content changes, but a takedown still needs a real purge
Purge fan-out via control planeControl plane publishes purge records; each PoP polls a per-PoP feed and deletes locallySeconds of propagation; needs acknowledgements for an audit trail

Use versioned, immutable URLs for the normal case and the control-plane purge feed for takedowns; each PoP acknowledges the purge id so the service can show "purged everywhere" with confidence.

How is a dead server or a dead PoP hidden from viewers?

Inside a PoP, health checks every second remove a server from the hash ring; consistent hashing means only that server's objects move, and they are refetched from the shield on first miss. A whole PoP failing is handled by steering: anycast withdraws its route and DNS stops returning it, so new sessions land on the next nearest PoP with 20 to 30 ms more latency; in-flight players simply retry the segment, which the adaptive player does anyway.

6. What a strong answer sounds like

  • Lead with the two numbers that matter, hit rate and origin load, and show how hashing inside the PoP, admission control and the shield tier each move them.
  • Quote 100 Tbps, 500 Gbps per PoP, 150 Gbps per server, and the 1 percent of objects that carry 90 percent of traffic.
  • Say that segments are immutable so the cache has no invalidation problem beyond takedowns.
  • Expect follow-ups on peering and transit cost, on TLS termination at the edge, on signed URLs for paid content, and on how you would measure hit rate by bytes rather than requests.
  • A common mistake is to let every edge server cache independently; the PoP-level hash is the single biggest capacity win.

02Where this question was reported