Build a CDN (13 scenes)
Scene 12 · Design your CDN configuration
Capstone: pick TTL, Vary, purge strategy, shield, and bypass for static / authenticated API / video / real-time workloads — verifier traces every choice back to a scene.
Previously
Now that you can read the dashboard, you can design the configuration that produces a healthy one for a real workload — drop a workload card on the canvas and read the verifier as the rubric.
Scene 12
Design your CDN configuration
Diagram
LEFT — palette: Cache-Control header, Vary axes, surrogate-keys, shield/bypass, purge strategy. CENTER — active workload card (title, traffic, SLO) and the user→POP→[shield]→origin dataflow shaped by the current config. RIGHT — verifier: four score tiles (origin RPS, p95, hit ratio, worst staleness) and a verdict list — every line cites the earlier scene that justifies it. Re-introductions for terms many scenes back: TTL — how long the edge keeps a fresh copy (scene 4). Vary — extra request headers in the cache key; cardinality footgun (scene 8). surrogate key — atomic-purge tag attached to multiple cached objects (scene 7). shield — one POP between many POPs and origin; absorbs thundering herd (scene 9). bypass — straight-through route, never cached (scene 10).
Sources
- docCloudflare Learning Center — full CDN reference
- docFastly Documentation Hub
- RFCRFC 9111 — HTTP Caching (the contract)
- RFCRFC 5861 — stale-while-revalidate / stale-if-error
- blogCloudflare: Cache Reserve (persistent tier behind Tiered Cache)
- talkFastly: Caching at the Edge tech talks
- blogIlya Grigorik — High Performance Browser Networking, Ch. 11 (HTTP Caching)
Empty canvas with one preset workload card already placed (static-asset site). Watch the four workloads roll past — each canvas snaps to the honest preset and the verifier nods, citing the scene that justifies each choice.
Implementation
Config.build
the CDN-config DSL — one knob per earlier scene
1config = {2 cacheControl: f"{public_or_private}, "3 f"max-age={maxAgeSec}, " # browser TTL4 f"s-maxage={sMaxAgeSec}, " # edge TTL5 f"stale-while-revalidate={swrSec}, "6 f"{'no-store' if noStore else ''}",7 vary: varyAxes, # cache-key fan-out8 surrogateKeys: tags, # atomic purge group9 shield: shieldEnabled, # collapse the herd10 bypass: bypass, # never cache this route11 purge: purgeStrategy, # url | surrogate | zone12}
Verifier.verify
scores a config against the workload's SLO; cites scenes
1def verify(workload, config):2 originRps = estimateOriginRps(workload, config)3 hitRatio = estimateHitRatio(workload, config) # bytes for video4 staleness = worstCaseStaleness(config) # max-age + swr5 leakRisk = perUserInSharedCache(workload, config)67 verdicts = []8 if config.vary contains 'User-Agent' or 'Cookie':9 verdicts += fail('cardinality explosion', scene=8)10 if leakRisk and not (config.bypass or config.noStore):11 verdicts += fail('per-user data in shared cache', scene=10)12 if config.swrSec > 0 and workload.stalenessIsIncident:13 verdicts += fail('SWR ships the bug for swrSec', scene=6)14 if config.purge == 'zone' and not config.shieldEnabled:15 verdicts += fail('cold-cache stampede on origin', scene=7)16 return { originRps, hitRatio, staleness, leakRisk, verdicts }
Workload.slo
what number the verifier should weigh for this workload
1workloads = {2 'static': slo(p95Ms=50, metric='requestHitRatio',3 leakRisk=False, stalenessIsIncident=False),4 'authApi': slo(p95Ms=200, metric='originRps',5 leakRisk=True, stalenessIsIncident=False),6 'video': slo(p95Ms=200, metric='byteHitRatio',7 leakRisk=False, stalenessIsIncident=False),8 'realtime': slo(p95Ms=200, metric='originRps',9 leakRisk=False, stalenessIsIncident=True),10}11# the verifier reads workload.metric to know which dial12# to weigh — request hit ratio for static, BYTE hit ratio13# for video, staleness for realtime, leakRisk for authApi.