01

Requirements & scope

Problem Statement & Requirements

Design a globally distributed Content Delivery Network that caches and serves static and dynamic content from edge locations closest to users — similar to CloudFront, Cloudflare, Akamai, or Fastly.

Functional Requirements

  • Cache and serve static assets — images, videos, CSS, JS, fonts, HTML pages
  • Support dynamic content acceleration — API responses, personalized pages via edge compute
  • Content purge / invalidation — origin can invalidate cached content globally within seconds
  • Custom domain support — customers bring their own domains with TLS (SNI-based)
  • TLS termination at the edge — HTTPS everywhere, automatic certificate management
  • Origin shielding — collapse multiple edge requests into a single origin fetch
  • Geo-restriction — block or allow content by country/region
  • Real-time analytics — hits, misses, bandwidth, latency, error rates per PoP
  • Edge compute — run lightweight functions (like Cloudflare Workers) at the edge

Non-Functional Requirements

  • Ultra-low latency — serve cached content in < 10 ms (p50), < 50 ms (p99) globally
  • High availability — 99.999% uptime (< 5 min downtime/year)
  • Massive throughput — handle 100M+ requests/second globally
  • Global reach — 200+ Points of Presence (PoPs) across 50+ countries
  • Cache hit ratio — target > 95% for static content
  • Instant purge — invalidate content globally within < 5 seconds
  • DDoS protection — absorb multi-Tbps volumetric attacks at the edge

Out of Scope

  • Full WAF (Web Application Firewall) rule engine details
  • Detailed DNS infrastructure design (covered as a component, not the focus)
  • Video live-streaming specific protocols (HLS/DASH segmentation)
02

Scale estimations

Scale Estimations

Traffic

Metric Value
Total requests / second (global) 100M RPS
Peak requests / second 300M RPS (3x during events)
Number of PoPs 250
Avg requests per PoP 400K RPS (uneven — top 20 PoPs handle 60%)
Cache hit ratio (static) 95%
Cache hit ratio (dynamic) 60-70% (with edge compute)
Origin requests / second 5M RPS (5% miss rate on 100M)

Bandwidth

Metric Value
Average response size 50 KB (mix of images, JS, API)
Total egress bandwidth 100M × 50 KB = 5 TB/s = 40 Tbps
Per-PoP average bandwidth 40 Tbps / 250 = 160 Gbps per PoP
Top PoPs bandwidth 500 Gbps - 1 Tbps
Monthly data transfer 5 TB/s × 86,400 × 30 = ~13 EB/month

Storage (Per PoP)

Metric Value
Hot content (frequently accessed) ~2-10 TB per PoP (SSD)
Warm content (less frequent) ~50-200 TB per PoP (HDD)
Total unique content across all origins Hundreds of PB
Content served from cache (by volume) ~95% (power-law distribution)

Hardware Estimate (Per PoP — Medium Tier)

Component Spec
Edge servers 20-100 servers per PoP
CPU per server 32-64 cores (TLS termination + edge compute)
RAM per server 256-512 GB (in-memory hot cache)
SSD per server 4-8 TB NVMe (warm cache)
HDD per server 20-50 TB (cold cache tier, large PoPs only)
Network per server 25-100 Gbps NIC
PoP uplink 400 Gbps - 2 Tbps (peering + transit)
03

Layered architecture

High-Level Architecture

High-Level ArchitectureExcalidraw diagram · editable shapes · reveal step by stepExplore

Component Breakdown

Component BreakdownExcalidraw diagram · editable shapes · reveal step by stepExplore
04

API & contracts

API Design

Customer Configuration API

EXAMPLE
POST /api/v1/distributions
Content-Type: application/json

Request:
{
  "name": "my-website-cdn",
  "origins": [
    {
      "domain": "origin.example.com",
      "protocol": "https",
      "port": 443,
      "path": "/assets",
      "weight": 100,               // for origin failover / load balancing
      "timeout_ms": 30000,
      "retry_count": 2
    }
  ],
  "domains": ["cdn.example.com", "assets.example.com"],
  "cache_behaviors": [
    {
      "path_pattern": "/images/*",
      "ttl_seconds": 86400,         // 24 hours
      "compress": true,
      "allowed_methods": ["GET", "HEAD"],
      "cache_key_includes": ["query_string", "accept_encoding"]
    },
    {
      "path_pattern": "/api/*",
      "ttl_seconds": 0,             // pass-through to origin
      "allowed_methods": ["GET", "POST", "PUT", "DELETE"],
      "forward_headers": ["Authorization", "Accept"]
    }
  ],
  "tls": {
    "certificate": "auto",          // auto-provision via Let's Encrypt
    "min_protocol_version": "TLSv1.2",
    "http2": true
  },
  "geo_restriction": {
    "type": "whitelist",
    "countries": ["US", "CA", "GB", "DE", "JP"]
  }
}

Response (201 Created):
{
  "distribution_id": "d-abc123",
  "status": "deploying",
  "cdn_domain": "d-abc123.cdn.net",
  "custom_domains": ["cdn.example.com"],
  "created_at": "2026-04-03T10:00:00Z",
  "estimated_deploy_time_seconds": 120
}

Purge / Invalidation API

EXAMPLE
POST /api/v1/distributions/{distribution_id}/invalidations
Content-Type: application/json

Request:
{
  "paths": [
    "/images/hero.jpg",           // exact path
    "/css/*",                     // wildcard
    "/*"                          // purge everything (use sparingly)
  ]
}

Response (202 Accepted):
{
  "invalidation_id": "inv-xyz789",
  "status": "in_progress",
  "paths": ["/images/hero.jpg", "/css/*"],
  "created_at": "2026-04-03T10:05:00Z",
  "estimated_completion_seconds": 5
}

Analytics API

EXAMPLE
GET /api/v1/distributions/{distribution_id}/analytics
    ?start=2026-04-03T00:00:00Z
    &end=2026-04-03T23:59:59Z
    &granularity=1h
    &metrics=requests,bandwidth,cache_hit_ratio,p99_latency

Response (200 OK):
{
  "distribution_id": "d-abc123",
  "data_points": [
    {
      "timestamp": "2026-04-03T00:00:00Z",
      "requests": 45000000,
      "bandwidth_gb": 2250,
      "cache_hit_ratio": 0.967,
      "p99_latency_ms": 28,
      "error_rate_4xx": 0.012,
      "error_rate_5xx": 0.0003
    },
    ...
  ]
}
05

Data model

Data Model

Distribution Configuration

Distribution ConfigurationExcalidraw diagram · editable shapes · reveal step by stepExplore

Cache Entry (Per Edge Server — In-Memory/On-Disk)

Cache Entry (Per Edge Server — In-Memory/On-Disk)Excalidraw diagram · editable shapes · reveal step by stepExplore

Access Log Record (Streamed to Analytics)

Access Log Record (Streamed to Analytics)Excalidraw diagram · editable shapes · reveal step by stepExplore
06

Core design decisions

Core Design Decisions

Decision 1: Request Routing — How Users Reach the Nearest PoP

This is the most critical decision. Every request must land on the optimal PoP.

Option A: DNS-Based GeoDNS
Option A: DNS-Based GeoDNSExcalidraw diagram · editable shapes · reveal step by stepExplore
Pros Cons
Simple, well-understood Routing based on DNS resolver location, not user
Works with any client Can't react to real-time congestion
No special client support needed DNS caching delays failover
Option B: Anycast IP Routing
Option B: Anycast IP RoutingExcalidraw diagram · editable shapes · reveal step by stepExplore
Pros Cons
Routes based on actual network topology BGP convergence can take 30-90s on failure
Automatic failover via BGP withdrawal TCP connections break on route changes
No DNS dependency for routing Less granular control than DNS
Inherently absorbs DDoS (spreads across PoPs) Can't control per-customer routing easily
Option C: Hybrid (DNS + Anycast) — Recommended
Option C: Hybrid (DNS + Anycast) — RecommendedExcalidraw diagram · editable shapes · reveal step by stepExplore

Decision 2: Cache Hierarchy — Multi-Tier Caching

Decision 2: Cache Hierarchy — Multi-Tier CachingExcalidraw diagram · editable shapes · reveal step by stepExplore

Decision 3: Cache Invalidation Strategy

Decision 3: Cache Invalidation StrategyExcalidraw diagram · editable shapes · reveal step by stepExplore
07

Request flows

Detailed Flow Diagrams

Cache Hit Flow (Happy Path — 95% of Requests)

Cache Hit Flow (Happy Path — 95% of Requests)Excalidraw diagram · editable shapes · reveal step by stepExplore

Cache Miss Flow (with Origin Shield)

Cache Miss Flow (with Origin Shield)Excalidraw diagram · editable shapes · reveal step by stepExplore

Purge / Invalidation Flow

Purge / Invalidation FlowExcalidraw diagram · editable shapes · reveal step by stepExplore
08

Performance & caching

Workshop note · added for the website’s common reading format

Start with the dominant access pattern of Content Delivery Network. Customer origin is one place to inspect capacity and tail latency. Measure before introducing a cache: define the cache key, invalidation policy, stale-data budget, and cold-start behavior.

Batch independent work where the latency budget allows it. Bound queues and concurrency, and verify that an optimization does not move the bottleneck to a dependency.

09

Advanced design

TLS at the Edge

TLS Termination Architecture

TLS Termination ArchitectureExcalidraw diagram · editable shapes · reveal step by stepExplore

OCSP Stapling

EXAMPLE
Traditional OCSP:
  Client → CDN → serve content
  Client → CA's OCSP responder → "is cert still valid?"  (SLOW, privacy leak)

OCSP Stapling:
  CDN periodically fetches OCSP response from CA
  CDN staples (attaches) OCSP response to TLS handshake
  Client gets cert + validity proof in one step → faster, more private

Edge Compute

Architecture

ArchitectureExcalidraw diagram · editable shapes · reveal step by stepExplore

Edge Compute Deployment Flow

Edge Compute Deployment FlowExcalidraw diagram · editable shapes · reveal step by stepExplore

DDoS Mitigation at the Edge

DDoS Mitigation at the EdgeExcalidraw diagram · editable shapes · reveal step by stepExplore
10

Edge cases

Handling Edge Cases

Thundering Herd (Cache Stampede)

EXAMPLE
Problem: Popular object expires → 10,000 concurrent requests all miss cache
         → all 10,000 hit origin simultaneously → origin overload

Solution: Request Coalescing (aka Request Collapsing)

  Request 1 (cache miss) → lock: I'll fetch from origin
  Request 2 (cache miss) → wait, someone is already fetching
  Request 3 (cache miss) → wait, someone is already fetching
  ...
  Request 10,000 (cache miss) → wait

  Origin receives: 1 request (not 10,000)
  Response returns → populate cache → serve all 10,000 waiters

  Implementation: per-cache-key mutex with a wait queue
  Timeout: if origin is slow (> 5s), serve stale content if available

Stale Content During Origin Failure

EXAMPLE
Problem: Origin is down → cache misses can't be filled → users get errors

Solution: Stale-If-Error

  Cache-Control: max-age=60, stale-if-error=86400

  Normal: serve fresh content (age < 60s)
  Origin down: serve stale content (age < 86400s) + add Warning header
  Completely expired: return 502/504 with custom error page

  Edge behavior:
  1. Cache miss → try origin → timeout/5xx
  2. Check stale cache → if stale copy exists, serve it
  3. Add header: Warning: 110 "Response is Stale"
  4. Log origin failure → alert monitoring

Hot Object / Viral Content

EXAMPLE
Problem: One object (e.g., breaking news image) gets 1M RPS at a single PoP

Solution: Multi-layer approach
  1. RAM cache (L1) absorbs most reads — kernel-level serving (io_uring / sendfile)
  2. If single server saturates → PoP-level LB distributes across all servers
  3. All servers in PoP independently cache the object (no shared cache needed)
  4. Pre-warm: detect virality (rapid access count increase) → proactively
     push to all PoPs before they miss

  Key insight: CDN edge servers are embarrassingly parallel for reads.
  Unlike databases, every server can independently cache + serve the same object.

Cache Poisoning

EXAMPLE
Problem: Attacker sends crafted request → poisoned response gets cached
         → all subsequent users get the poisoned response

Attack: GET /page HTTP/1.1
        Host: cdn.example.com
        X-Forwarded-Host: evil.com      ← if origin reflects this, cached for all users

Mitigations:
  1. Strict cache key construction — only include documented Vary headers
  2. Never cache responses with Set-Cookie headers
  3. Strip untrusted headers before forwarding to origin
  4. Validate Cache-Control directives from origin (ignore private/no-store only for intended objects)
  5. Cache key includes Host header — prevents cross-domain poisoning
  6. WAF rules to detect header injection attempts

Partial Content / Range Requests (Video Seeking)

EXAMPLE
Client: GET /video.mp4
        Range: bytes=1000000-2000000

Edge behavior:
  Option A: Cache full object, serve range from cache
    + Simple — one cached copy serves any range
    - Wastes bandwidth on first fetch if user only watches 30s of a 2-hour video

  Option B: Cache range slices (e.g., 1 MB chunks)
    + Only fetch what's needed
    - Complex cache management, many small cache entries
    - Reassembly overhead

  Recommended: Hybrid
    → Small objects (< 10 MB): cache full object
    → Large objects (> 10 MB): cache in fixed-size slices (2 MB)
    → Use internal Range requests to origin for slices
    → Serve client's Range from assembled slices
11

Tradeoffs

Tradeoffs & Design Decisions Summary

Decision Option A Option B Chosen Why
Request Routing DNS-based GeoDNS Anycast BGP Hybrid (Anycast + DNS) Anycast for coarse routing + DDoS absorption; DNS for fine-grained control
Cache Hierarchy Single-tier edge only Multi-tier (edge + shield) Multi-tier Origin shield reduces origin load 30x; justified for any serious CDN
Cache Eviction Pure LRU LFU (frequency-based) Hybrid LRU+LFU (ARC/W-TinyLFU) LRU evicts popular items on scan; LFU is slow to adapt; hybrid is best
Cache Invalidation TTL-only Active purge TTL + SWR + Surrogate Keys TTL for baseline; SWR for zero-latency; tags for surgical invalidation
TLS Termination At origin At edge Edge Eliminates 100-200 ms per new connection; enables HTTP/2 multiplexing
Edge Compute Containers (Lambda@Edge) V8 Isolates (Workers) V8 Isolates Sub-ms cold start vs 100ms+; thousands per process; better for request-level compute
Cache Storage In-memory only Disk + memory tiered Tiered (RAM → SSD → HDD) Memory alone can't hold enough; SSD gives 10x capacity at ~5 ms; HDD for cold tail
Origin Protocol HTTP/1.1 persistent HTTP/2 multiplexed HTTP/2 Single connection, multiplexed streams; reduces origin connection overhead
Content Compression gzip Brotli Both (Brotli preferred) Brotli: 20-30% smaller than gzip for text; pre-compress at cache time
PoP Failure DNS failover (30-60s) BGP withdrawal (30-90s) BGP + health-check triggered DNS BGP is automatic; DNS gives faster override; combined gives < 30s failover
12

Reliability & fault tolerance

Reliability & Fault Tolerance

Single Points of Failure & Mitigations

Single Points of Failure & MitigationsExcalidraw diagram · editable shapes · reveal step by stepExplore

Graceful Degradation Hierarchy

EXAMPLE
Level 1 (single server failure):
  → LB routes around it. Zero user impact. Auto-heals.

Level 2 (partial PoP degradation):
  → Remaining servers absorb traffic. Increased latency at that PoP.
  → Alert ops team.

Level 3 (full PoP failure):
  → BGP withdrawal in ~30s. Users rerouted to next-closest PoP.
  → Latency increases by ~10-50 ms. No data loss.

Level 4 (origin shield failure):
  → Edges bypass shield, fetch directly from origin.
  → Origin sees higher load but still functional.

Level 5 (customer origin failure):
  → Serve stale cached content (stale-if-error).
  → Custom error pages for truly uncached content.
  → Alert customer via webhook.

Level 6 (control plane failure):
  → Edges continue serving with last-known config.
  → No config updates or purges until control plane recovers.
  → Edge-to-edge gossip for critical updates (if implemented).
13

Production architecture

Full System Architecture (Production-Grade)

Full System Architecture (Production-Grade)Excalidraw diagram · editable shapes · reveal step by stepExplore
14

Further exploration

Workshop note · added for the website’s common reading format

Rebuild Content Delivery Network from memory, then change one assumption: ten times more traffic, a new region, or a stricter consistency requirement. Which component must change first—and which does not?

Compare Edge PoP with the same boundary in a related design. Write down one alternative you rejected, what it would simplify, and when you would choose it instead. Follow the source link at the end of this article to explore the original document.

15

Interview playbook

Interview Tips

  1. Start with the two-sentence pitch — "A CDN is a globally distributed cache. It serves content from the edge closest to users, reducing latency from ~200 ms (origin) to ~5 ms (edge cache hit)."

  2. Draw the DNS → Edge → Shield → Origin hierarchy first — This is the backbone. Explain each tier's purpose and cache hit contribution.

  3. Discuss Anycast deeply — Most candidates only mention DNS routing. Explain how Anycast works (same IP, BGP announces from every PoP), why it's elegant (automatic failover, DDoS dilution), and its limitations (TCP connection breaks on route change).

  4. Cache key construction is subtle — Don't handwave. Explain how the cache key is built from path + query + Vary headers + distribution ID. Mention cache poisoning risks.

  5. Explain the thundering herd problem and request coalescing — This shows you've thought about real production issues, not just the happy path.

  6. Stale-while-revalidate is a killer feature — Explain the tradeoff: users always get fast responses, content is at most one cycle stale, and origins never block the user.

  7. TLS at the edge is non-negotiable — Quantify: terminating TLS at edge vs origin saves 1-2 RTTs × distance. For a user 200 ms from origin but 5 ms from edge, that's 390 ms saved on TLS 1.2.

  8. Mention edge compute — This differentiates you. Explain V8 isolates (sub-ms cold start), use cases (A/B testing, auth, geolocation), and why they're superior to containers for request-level compute.

  9. Discuss cost model — CDN economics matter. Bandwidth is the main cost (peering vs transit). Explain why CDNs negotiate private peering with ISPs and why edge cache capacity planning uses power-law distributions.

  10. End with DDoS — "A CDN is inherently a DDoS mitigation layer. With 250 PoPs each handling Tbps, the network absorbs attacks by distributing them. The origin never sees the attack traffic."