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)
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) |
Layered architecture
Phase 1 of 4 · Client & edge
Start with the entry points
First, define who uses the system and where requests enter. This is the boundary of the design, not yet a complete request path.
- Browser
- Use versioned asset URLs where possible so cached content can remain immutable.
- DNS / Anycast
- Route requests to a healthy point of presence while accounting for geography and network paths.
This first layer defines the system boundary. The next chapters add application logic and data dependencies. After examining the request paths and tradeoffs, we will add operational safeguards and bring the complete architecture together.
API & contracts
Phase 2 of 4 · Application & compute
Add the application logic
Keep the entry points and add the services that do the work. Give each service a clear responsibility before defining its contracts. Storage and background dependencies come next.
- Edge PoP
- Terminate TLS and serve cache hits without contacting the origin.
- Origin shield
- Collapse repeated cache misses before they fan out to the customer origin.
API Design
Customer Configuration API
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
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
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
},
...
]
}Data model
Phase 3 of 4 · Data & async work
Connect data and background work
The services now need their dependencies: durable state, fast lookups, or work that continues outside a request. Separate these responsibilities rather than treating every component as a database.
- Customer origin
- Fetch fresh objects from the authoritative origin when the cache hierarchy misses.
- Configuration
- Define cache keys carefully to avoid leaking personalized responses between users.
- Purge service
- Distribute invalidations and track convergence; purge is not an instantaneous global operation.
Data Model
Distribution Configuration
Cache Entry (Per Edge Server — In-Memory/On-Disk)
Access Log Record (Streamed to Analytics)
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
| 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
| 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
Decision 2: Cache Hierarchy — Multi-Tier Caching
Decision 3: Cache Invalidation Strategy
Request flows
Detailed Flow Diagrams
Cache Hit Flow (Happy Path — 95% of Requests)
Cache Miss Flow (with Origin Shield)
Purge / Invalidation Flow
Performance & caching
A popular object expiring at many edges can send a wave of simultaneous misses to the origin. Collapse concurrent requests for the same object and consider staggered expiry or permitted stale serving. The cache key must include the request attributes that change the representation; otherwise one person’s response can be served to another.
Advanced design
TLS at the Edge
TLS Termination Architecture
OCSP Stapling
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 privateEdge Compute
Architecture
Edge Compute Deployment Flow
DDoS Mitigation at the Edge
Edge cases
Handling Edge Cases
Thundering Herd (Cache Stampede)
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 availableStale Content During Origin Failure
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 monitoringHot Object / Viral Content
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
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 attemptsPartial Content / Range Requests (Video Seeking)
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 slicesTradeoffs
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 |
Reliability & fault tolerance
Phase 4 of 4 · Operations & resilience
Add operational safeguards
With the request paths and tradeoffs established, add the controls that help detect trouble and keep the system operating. The final diagram retains every layer introduced so far.
- Edge operations
- Observe cache hit rate, stale responses, TLS failures, and origin amplification.
Reliability & Fault Tolerance
Single Points of Failure & Mitigations
Graceful Degradation Hierarchy
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).Production architecture
High-Level Architecture
Component Breakdown
Full System Architecture (Production-Grade)
Further exploration
Publish a new application release containing HTML and versioned JavaScript files. Decide which files may be cached for a long time and which need rapid revalidation. Then roll back. A good cache policy should let both old and new HTML find the assets they reference throughout the transition.
Interview playbook
Interview Tips
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)."
Draw the DNS → Edge → Shield → Origin hierarchy first — This is the backbone. Explain each tier's purpose and cache hit contribution.
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).
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.
Explain the thundering herd problem and request coalescing — This shows you've thought about real production issues, not just the happy path.
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.
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.
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.
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.
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."