What is a CDN?
A Content Delivery Network (CDN) is a distributed network of edge servers placed close to users globally. Instead of every request traveling to a single origin server, CDN edge servers cache content and serve it from the nearest location — reducing latency from 200ms to 5ms for cached content. CDNs also absorb traffic spikes, protect the origin from DDoS, and handle SSL termination. Cloudflare, Akamai, and AWS CloudFront are the major CDN providers.
Requirements
- Serve static assets (images, JS, CSS) with <10ms latency globally
- Cache hit rate >95% for popular content
- Cache invalidation: update propagated to all edges within 60 seconds
- Origin offload: >95% of requests served from cache (origin receives only 5%)
- Handle 1M requests/second across all edges
- Support HTTPS at the edge (SSL termination, TLS 1.3)
Architecture
User (Brazil) → DNS → CDN Edge (São Paulo)
↓ cache HIT
[Return cached content]
↓ cache MISS
CDN Shield (Regional Cache, US-East)
↓ shield MISS
Origin Server (US-East)
Hierarchy:
Edge (50-100 PoPs globally) — closest to users
Shield (5-10 regional hubs) — collapses duplicate origin requests from many edges
Origin — your application server or S3 bucket
Cache Key Design
The cache key determines when two requests are served the same cached response:
Default cache key: scheme + host + path https://cdn.example.com/images/product-123.jpg → single cached entry Including query params: /search?q=laptop&page=1 → unique cache entry per query /search?q=laptop&page=2 → different cache entry (sort query params alphabetically to normalize: q=laptop&page=1 == page=1&q=laptop) Vary header: Vary: Accept-Encoding → separate cache entries for gzip vs identity Vary: Accept → separate entries for JSON vs HTML Vary: Accept → separate entries for WebP vs JPEG for images
Cache Control Headers
# Never cache (private/dynamic content) Cache-Control: private, no-store # or Cache-Control: no-cache # revalidate every time # Cache for 1 hour, serve stale for 1 day while revalidating Cache-Control: public, max-age=3600, stale-while-revalidate=86400 # Immutable: cache forever (content-addressed URLs) Cache-Control: public, max-age=31536000, immutable # Use for: /static/app.a1b2c3d4.js (hash in filename) # CDN-specific: edge cache for 1 day, browser cache for 1 hour Cache-Control: public, max-age=3600, s-maxage=86400
Cache Invalidation
Two strategies:
URL versioning (preferred): embed a hash or version in the URL. When the asset changes, the URL changes. Old URLs expire naturally. Zero propagation delay. Example: /static/bundle.a1b2c3.js → /static/bundle.d4e5f6.js.
Purge API: call the CDN purge API to immediately invalidate a URL across all edges. Used for content that can’t be versioned (e.g., /api/prices/product-123). CloudFront purge propagates in 10-60 seconds. Use for emergency invalidation, not routine deployment.
Origin Protection
The shield layer prevents cache stampedes (many edges simultaneously requesting the same origin URL after a cache miss):
Request collapse: when 100 edge nodes miss cache simultaneously for the same URL: - Without shield: 100 origin requests - With shield: edges forward to the regional shield, which collapses to 1 origin request - Shield serves all 100 edges from its local cache Origin failover: If origin returns 5xx: serve stale cache (if stale-while-revalidate is set) If no stale content: return CDN error page Configure: if origin fails, try backup origin
Key Design Decisions
- Two-tier hierarchy (edge + shield) — eliminates origin thundering herd from cache misses across many PoPs
- Immutable cache headers for hashed assets — zero invalidation cost, permanent CDN caching
- s-maxage separate from max-age — CDN and browser can have different TTLs (CDN longer)
- Vary: Accept for format negotiation — serve WebP to Chrome, JPEG to Safari, without separate URLs
- Purge only for emergencies — URL versioning is the right default; purge is operationally expensive
{“@context”:”https://schema.org”,”@type”:”FAQPage”,”mainEntity”:[{“@type”:”Question”,”name”:”How does a CDN edge server decide what to cache?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”The CDN caches a response when: (1) the response status is cacheable (200, 301, 404 — yes; 302, 500 — no by default), (2) the response has Cache-Control: public or no Cache-Control: private/no-store header, and (3) the method is GET or HEAD (POST responses are never cached). The cache key defaults to scheme + host + path. Add query parameters to the key for dynamic pages; use Vary header to cache separate copies per Accept-Encoding or Accept (WebP vs JPEG).”}},{“@type”:”Question”,”name”:”What is the difference between max-age and s-maxage?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”max-age controls browser caching; s-maxage controls CDN (shared cache) caching. Cache-Control: max-age=3600, s-maxage=86400 means the browser caches for 1 hour but the CDN caches for 1 day. After s-maxage expires, the CDN revalidates with the origin; after max-age expires, the browser revalidates with the CDN. Use this to let CDN cache longer (it can revalidate cheaply at the edge) while forcing browsers to get fresher content.”}},{“@type”:”Question”,”name”:”How do you invalidate CDN cache without deploying?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Option 1: URL versioning — embed a content hash in the filename (/bundle.a1b2c3.js). When the file changes, the hash changes, the URL changes, and the old cached version expires naturally. No purge needed. This is the best approach for static assets. Option 2: Purge API — call CloudFront/Cloudflare’s purge endpoint with the URL(s) to invalidate. Propagates in 10-60 seconds across all edges. Use for content that can’t be versioned (HTML pages, API responses). Purging has cost implications and operational overhead — URL versioning is preferred.”}},{“@type”:”Question”,”name”:”What is stale-while-revalidate and why is it useful?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Cache-Control: stale-while-revalidate=86400 means: after max-age expires, serve the stale cached version immediately while revalidating with the origin in the background. The user gets a fast response (no origin round-trip), and the cache is updated for the next request. Without it: after max-age expires, the user waits for origin revalidation (adds latency on every TTL boundary). Use this for content that is slightly stale is acceptable — news articles, product listings, non-personalized pages.”}},{“@type”:”Question”,”name”:”How does a CDN shield layer reduce origin load?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Without shield: 50 edge PoPs each miss cache simultaneously for a popular URL → 50 origin requests. With shield: all 50 edges forward their misses to a single regional shield node, which makes 1 origin request and serves all 50 edges. This is "request collapsing." The shield acts as a mid-tier cache. CloudFront calls this Origin Shield; Fastly calls it shielding. Enable it for any high-traffic asset to dramatically reduce origin bandwidth and protect against cache stampedes during traffic spikes.”}}]}
CDN design and content delivery architecture is discussed in Netflix system design interview guide.
CDN and CloudFront architecture design is covered in Amazon system design interview questions.
Global content delivery and CDN design is discussed in Meta system design interview preparation.