CDN Design & Edge Computing
PoP placement, cache hierarchies, edge functions, Cache-Control headers, and origin shield design.
4 Exercises
12 Concept Checks
~90 min total
System Design
Session Progress
0 / 4 completed
Cache-Control Header Design
A media site serves 4 asset types: content-hashed JS/CSS bundles (e.g. app.3f8a2c.js), API JSON responses, user profile photos, and live sports scores. Each has radically different staleness tolerance — one wrong Cache-Control header causes stale data or wasted origin hits.
Cache-Control per Asset Type
Browser
→
CDN Edge
→ on miss →
Origin
← Cache-Control header controls each layer
Concept Check — 3 questions
Q1. Content-hashed JS bundle (e.g. app.3f8a2c.js — hash changes on every deploy). Best Cache-Control?
Ano-cache — always revalidate with origin on every request
BCache-Control: public, max-age=31536000, immutable — cache 1 year, never revalidate
CCache-Control: private, max-age=3600 — cache for 1 hour in browser only
Dno-store — never cache this file anywhere
Q2. Live sports scores must never be served from cache. Which directive achieves this?
ACache-Control: max-age=1 — cache for only 1 second
BCache-Control: private — only cache in the browser
CCache-Control: no-cache, no-store — bypass all caches completely
DCache-Control: max-age=0 — treat as expired immediately
Q3. The s-maxage directive in Cache-Control controls which cache layer?
ABrowser cache only — s-maxage overrides browser max-age
BCDN and shared/proxy caches only — browsers use max-age instead
CBoth browser and CDN — s-maxage applies everywhere
DDatabase cache — s-maxage controls server-side cache TTL
30s-stale API: max-age=30, stale-while-revalidate=60 (serve stale while refreshing). User avatar: max-age=86400 (24h). Marketing homepage: max-age=0, s-maxage=300, stale-while-revalidate=3600. Cache busting: content-hashed filename (app.3f8a2c.js) creates a new URL on every deploy — old cached file is never served again; new URL starts fresh.
Open Design Challenge
Write Cache-Control headers for: a) an API response that can be 30s stale, b) a user avatar photo, c) a marketing homepage updated daily.
What is "cache busting" and how do content-hashed filenames implement it? What happens to old cached versions?
Design Vary header usage for content negotiation: same URL serving gzip vs brotli compressed content. How does the CDN cache both variants?
Concept score: 0/3
CDN PoP Placement Strategy
A streaming service has 80% of users in US-East, 15% in EU-West, 5% in APAC. Budget for 10 CDN PoPs. Current setup with 2 PoPs (NYC and London) causes APAC users 280ms latency and 40% cache miss rate from the long round-trip to London.
Traffic-Proportional PoP Distribution
80% US traffic → 6-7 PoPs
|
15% EU traffic → 2 PoPs
|
5% APAC traffic → 1-2 PoPs
→
Origin Shield → Origin
Concept Check — 3 questions
Q1. Given 80% US traffic, how many of the 10 PoPs should be in North America?
A2 PoPs — one per coast (East and West)
B6-7 PoPs — roughly proportional to traffic density with geographic spread
C10 PoPs — put all budget in the US since that's where most traffic is
D1 PoP — centralize in Chicago to minimize average US latency
Q2. An origin shield sits between CDN edge PoPs and the origin server. Its primary purpose is?
AAct as a security firewall filtering malicious requests
BHandle DNS routing between CDN regions
CCollapse cache misses from multiple edge PoPs into a single request to the origin
DAuthenticate users before serving cached content
Q3. An APAC user requests a video segment not cached in their regional PoP. The request path is?
AAPAC PoP miss → regional origin shield → origin server (NOT cross to US PoP)
BAPAC PoP miss → US PoP (to check US cache) → origin server
CAPAC PoP miss → directly to origin server, bypassing shields
DAPAC PoP returns a 404 since the content isn't cached locally
Optimal PoP placement for 10 nodes: NYC, LA, Chicago, Dallas, Miami, Seattle (6 US) + London, Frankfurt (2 EU) + Tokyo, Singapore (2 APAC). Pull model: CDN fetches content from origin on first miss, then caches. Push model: content is pre-populated before any requests. Origin load with 90% hit rate: 10M × 10% = 1M requests/hour reach origin.
Open Design Challenge
Design a PoP placement plan for the 10 PoPs optimizing for the given traffic distribution. Name specific cities and justify each choice.
How does the CDN "pull" model differ from "push" model? When do you use each for a streaming service?
Calculate origin load reduction: 10M requests/hour, 90% CDN hit rate. How many requests reach origin per hour and per second?
Concept score: 0/3
Edge Functions for Personalization
A news site wants to serve personalized homepages based on user auth status, language preference, and A/B test bucket. Traditionally this means a round-trip to the origin (50-200ms). Edge functions run at CDN PoPs and can serve personalized content in under 5ms.
Edge Function Personalization Flow
Request
→
Edge Function (reads cookies: auth, lang, ab_bucket)
→
cache key: URL+lang+ab+auth_status
serve cached HTML per user segment
Concept Check — 3 questions
Q1. An edge function runs at the CDN PoP. Its latency advantage vs going to the origin is?
ASame latency as origin — edge functions don't help
B10-40× faster: edge function executes in <5ms vs 50-200ms origin round-trip
C10× slower — edge functions add overhead compared to origin
DExactly 1ms — edge functions always run in exactly 1 millisecond
Q2. For edge-personalized pages, what should the CDN cache key be?
AURL only — one cache entry per page regardless of user
BURL + user ID — one cache entry per individual user
CURL + user segment (lang, ab_bucket, auth status) — not individual user ID
DNo caching — personalized content must always be dynamic
Q3. An edge function adds 8ms to each request (cold start). When is this NOT worth the overhead?
AFor static pages — edge functions are only useful for dynamic content
BWhen origin RTT savings are less than the edge function overhead — net latency is worse
CFor logged-in users — edge functions can't access session data
DNever — edge functions are always worth using
Edge routing by language: read Accept-Language header, rewrite URL to /en/ or /fr/ path, serve the cached language variant. Expired auth token: edge function validates JWT signature and expiry field; redirect to /login if invalid — no origin needed. ESI (Edge-Side Includes): compose a page from independently cached fragments — the header, body, and sidebar each have their own cache TTL.
Open Design Challenge
Write pseudo-code for an edge function that routes requests to different cached pages based on the Accept-Language header. Handle en, fr, and default fallback.
How do you handle stale user session cookies at the edge? If the auth JWT has expired, what does the edge function do without calling the origin?
Explain Edge-Side Includes (ESI): how does it compose a personalized page from independently cached fragments? Sketch the HTML include syntax.
Concept score: 0/3
CDN Cache Poisoning and Security
A security researcher discovers your CDN is serving malicious JavaScript to all users. Investigation reveals: an attacker sent a crafted HTTP request with Host: evil.com, causing the CDN to cache a poisoned response. Every subsequent request for the legitimate URL receives the poisoned JS.
Cache Poisoning Attack Vector
Attacker: GET /app.js + Host: evil.com
→
CDN caches poisoned response
→
Legitimate users request /app.js
→
All receive poisoned JS
Concept Check — 3 questions
Q1. Cache poisoning exploits what CDN misconfiguration?
AWeak HTTPS encryption allowing the attacker to decrypt traffic
BCDN includes unvalidated request headers in the cache key, allowing different responses to be cached per header value
CMissing rate limiting that lets attackers send unlimited requests
DNo authentication on the CDN admin panel
Q2. Which HTTP header should NEVER be included in the CDN cache key without strict validation?
AAccept-Encoding — this is safe to include for compression variants
BAccept-Language — this is safe to vary on for language personalization
CHost and X-Forwarded-Host — these can be forged to serve attacker-controlled content
DCache-Control — this controls caching behavior and is always safe
Q3. To detect cache poisoning in production, what monitoring should you implement?
ALog all HTTP requests to a central SIEM system
BCryptographic hash verification of served static assets with alerts on unexpected content changes
CRate limit all CDN requests to 100 per second globally
DDisable CDN caching for all JavaScript files
Cache poisoning vectors: Host header, X-Forwarded-Host, Accept-Encoding variations (attacker sends unusual encoding), X-Forwarded-For, "Fat GET" (body cached with GET). Mitigation: define strict cache key (URL + normalized headers only), strip/normalize headers at edge before caching. SRI: <script integrity="sha256-..."> — browser verifies the cryptographic hash before executing the script.
Open Design Challenge
List 5 HTTP headers that could be abused for cache poisoning and describe a specific mitigation for each.
Design a Content Security Policy (CSP) header that limits damage if a JS file is successfully poisoned. What directives would you include?
How does Subresource Integrity (SRI) prevent a poisoned cached script from executing? Write an example HTML tag with an SRI hash.
Concept score: 0/3