Art of Codeartofcode
LLeeaarrnniinngg
BBlloogg
TToooollss
GGaammeess AArreennaa
JJoobbss
LLiivvee CCoouurrsseess

Courses

  • System DesignHigh-level system design, one everyday scene at a time: 30 concepts and 15 interview rounds.712 lessons
All coursesTutorialsMy Learning

Categories

  • 01AI & Tools
  • 02Tutorials
  • 03Engineering
  • 04Reviews
  • 05Build Logs
  • 06Tales of Misfits
  • 07Opinion
  • 08Career
  • 09News

Read & write

All storiesEvery post, newest first.Write for usPublish your stories and earn from what you write.Writer leaderboardsWho is writing the most read posts.

Categories

  • PDF Tools25
  • Development09
  • Utilities10
  • Design04
  • Converters04
  • Generators02

Featured

JSON FormatterFormat, validate and minify JSON.Regex TesterTest patterns against live text.Merge PDFCombine PDFs in your browser.JWT DecoderRead a token’s header and claims.Password GeneratorStrong passwords, generated locally.Gradient GeneratorBuild CSS gradients visually.
All 53 tools

Play a round

DevdleOne developer word a day, six guesses.Python RushClassic snake, with coding icons to eat.Blink or BreakA quick test of your reflexes.
Games Arena

Learn with us

Live CoursesInstructor-led courses. Join a waitlist and be first in when one starts.LearningStructured programming courses with AI assistance and certificates.

System Design

26. CDNs

Lesson 16 of 16

26. CDNs

1
The picture to keep in your head
2
26.1 Why use a CDN?
3
26.2 What are edge locations (PoPs)?
4
26.3 Pull vs push CDN: what's the difference?
5
26.4 How do cache keys and headers work?
6
26.5 How does purging work?
7
26.6 What is an origin shield?
8
26.7 Can the CDN handle dynamic content?
9
26.8 How do CDNs deliver video (HLS, DASH)?
10
26.9 What happens when the CDN fails?
11
Memory card and where the analogy breaks
12
Practice: five levels
13
Interview questions
14
Solutions
15
Sources
16
Code lab
26. CDNs

Code lab

5 min read+10 XP

Code lab: Chapter 26

The full, tested code for this chapter. Press Run: every check should pass. Then change one number, run it again, and see which check breaks and why.

python

No tracks available

Lofi Player

artofcode

artofcode.in

The den of devs.

Stories, tools, games, and gear for developers.

Read the StoriesEExxpplloorree TToooollss
Art of Codeartofcode

Platform

  • BBlloogg
  • TToooollss
  • GGaammeess AArreennaa
  • CCoouurrsseess
  • LLeeaarrnniinngg
  • CCaammppuuss

Company

  • AAbboouutt UUss
  • JJoobbss && IInntteerrnnsshhiippss
  • CCoonnttaacctt

Legal

  • TTeerrmmss ooff SSeerrvviiccee
  • PPrriivvaaccyy PPoolliiccyy
  • RReeffuunndd PPoolliiccyy

Copyright © 2026 artofcode.in, All Rights Reserved.

IST·--:--

1"""Chapter 26: CDNs. Tested with Python 3, standard library only.
2
3Running example: the bookstore's website. Origin servers in Mumbai; readers all over
4India and abroad; book covers, JS/CSS bundles and author-interview videos.
5"""
6from urllib.parse import urlsplit, parse_qsl, urlencode
7
8
9# ---------- 26.1 latency ----------
10
11def page_load_ms(rtt_ms, round_trips):
12    """Time spent purely on round trips (connection setup + requests), ignoring bandwidth."""
13    return rtt_ms * round_trips
14
15
16def origin_load(requests_per_s, hit_ratio):
17    return requests_per_s * (1 - hit_ratio)
18
19
20# ---------- 26.4 cache keys and headers ----------
21
22TRACKING = ("utm_", "fbclid", "gclid")
23
24
25def cache_key(url, normalize=True):
26    parts = urlsplit(url)
27    if not normalize:
28        return url
29    params = [(k, v) for k, v in parse_qsl(parts.query) if not k.startswith(TRACKING)]
30    query = urlencode(sorted(params))
31    return f"{parts.netloc.lower()}{parts.path}" + (f"?{query}" if query else "")
32
33
34def parse_cache_control(header):
35    out = {}
36    for part in header.split(","):
37        part = part.strip().lower()
38        if not part:
39            continue
40        if "=" in part:
41            k, v = part.split("=", 1)
42            out[k] = int(v)
43        else:
44            out[part] = True
45    return out
46
47
48def cdn_ttl(header):
49    """How long a shared cache (the CDN) may keep it. None = don't cache."""
50    cc = parse_cache_control(header)
51    if cc.get("no-store") or cc.get("private"):
52        return None
53    if "s-maxage" in cc:
54        return cc["s-maxage"]
55    return cc.get("max-age")
56
57
58# ---------- an edge cache with TTLs, purge by URL and by tag ----------
59
60class Edge:
61    def __init__(self, origin):
62        self.origin = origin
63        self.store = {}                   # key -> (body, expires_at, tags, stale_window)
64        self.origin_fetches = 0
65
66    def get(self, url, now, origin_up=True):
67        key = cache_key(url)
68        hit = self.store.get(key)
69        if hit and now < hit[1]:
70            return hit[0], "HIT"
71        if not origin_up:
72            if hit and now < hit[1] + hit[3]:
73                return hit[0], "STALE"    # stale-if-error
74            return None, "ERROR"
75        body, header, tags = self.origin(url)
76        self.origin_fetches += 1
77        ttl = cdn_ttl(header)
78        if ttl is not None:
79            stale = parse_cache_control(header).get("stale-if-error", 0)
80            self.store[key] = (body, now + ttl, tags, stale)
81        return body, "MISS"
82
83    def purge_url(self, url):
84        self.store.pop(cache_key(url), None)
85
86    def purge_tag(self, tag):
87        for k in [k for k, v in self.store.items() if tag in v[2]]:
88            del self.store[k]
89
90
91# ---------- 26.6 origin shield ----------
92
93def origin_fetches_for_new_object(pops, shield):
94    """Every PoP gets a request for a brand-new cover. How many reach the origin?"""
95    return 1 if shield else pops
96
97
98# ---------- 26.8 video segments ----------
99
100def segments(duration_s, segment_s):
101    return -(-duration_s // segment_s)
102
103
104LADDER = [(240, 400), (360, 800), (480, 1_400), (720, 2_800), (1080, 5_000)]   # (height, kbps)
105
106
107def pick_rendition(measured_kbps, safety=0.8):
108    ok = [r for r in LADDER if r[1] <= measured_kbps * safety]
109    return ok[-1] if ok else LADDER[0]
110
111
112# ---------- 26.9 multi-CDN failover ----------
113
114def route(cdns_healthy, preference):
115    for name in preference:
116        if cdns_healthy.get(name):
117            return name
118    return "origin"
119
120
121# ---------- Level 4: caching a personal page ----------
122
123def buggy_account_page(user):
124    return f"<h1>Hello {user}</h1><p>Orders: ...</p>", "public, max-age=300", ()
125
126
127def fixed_account_page(user):
128    return f"<h1>Hello {user}</h1><p>Orders: ...</p>", "private, no-store", ()
129
130
131# ---------- checks ----------
132
133def run_checks():
134    # latency: a page needs ~6 round trips before the first useful bytes (DNS, TCP, TLS, HTML, CSS/JS)
135    guwahati_to_mumbai, guwahati_to_local_pop = 60, 8                 # assumed RTTs (ms)
136    assert page_load_ms(guwahati_to_mumbai, 6) == 360
137    assert page_load_ms(guwahati_to_local_pop, 6) == 48
138
139    # hit ratio drives origin load
140    assert round(origin_load(10_000, 0.95)) == 500
141    assert round(origin_load(10_000, 0.99)) == 100                  # 1 point of hit ratio = 5x less origin load
142
143    # cache keys: tracking params fragment the cache
144    urls = [f"https://BookStore.example/covers/42.jpg?utm_source=s{i}&size=m" for i in range(50)]
145    assert len({cache_key(u, normalize=False) for u in urls}) == 50
146    assert len({cache_key(u) for u in urls}) == 1
147    assert cache_key("https://b.example/s?q=dune&page=2") == cache_key("https://b.example/s?page=2&q=dune")
148
149    # headers
150    assert cdn_ttl("public, max-age=60, s-maxage=86400") == 86_400     # CDN keeps a day, browser a minute
151    assert cdn_ttl("private, max-age=600") is None
152    assert cdn_ttl("no-store") is None
153    assert cdn_ttl("public, max-age=31536000, immutable") == 31_536_000
154
155    # an edge in front of the origin
156    calls = {"n": 0}
157
158    def origin(url):
159        calls["n"] += 1
160        if "/covers/" in url:
161            return f"cover:{url}", "public, max-age=86400, stale-if-error=3600", ("book-42",)
162        if "/books/42" in url:
163            return "book page v1", "public, s-maxage=300, stale-if-error=600", ("book-42",)
164        return "x", "no-store", ()
165
166    edge = Edge(origin)
167    assert edge.get("https://b.example/books/42", now=0)[1] == "MISS"
168    assert edge.get("https://b.example/books/42?utm_source=ig", now=10)[1] == "HIT"
169    assert edge.get("https://b.example/books/42", now=301)[1] == "MISS"       # TTL expired
170    # origin down: serve stale within the stale-if-error window
171    assert edge.get("https://b.example/books/42", now=700, origin_up=False)[1] == "STALE"
172    assert edge.get("https://b.example/books/42", now=2_000, origin_up=False)[1] == "ERROR"
173    # purge by tag: the price changed, drop the page and the cover at once
174    edge.get("https://b.example/covers/42.jpg", now=3_000)
175    edge.get("https://b.example/books/42", now=3_000)
176    edge.purge_tag("book-42")
177    assert edge.get("https://b.example/books/42", now=3_001)[1] == "MISS"
178    assert edge.get("https://b.example/covers/42.jpg", now=3_001)[1] == "MISS"
179
180    # origin shield
181    assert origin_fetches_for_new_object(50, shield=False) == 50
182    assert origin_fetches_for_new_object(50, shield=True) == 1
183
184    # video: a 20-minute author interview in 6 s segments, 5 renditions
185    assert segments(1_200, 6) == 200
186    assert segments(1_200, 6) * len(LADDER) == 1_000
187    assert pick_rendition(4_000) == (720, 2_800)                        # 4 Mbps x 0.8 = 3.2 Mbps budget
188    assert pick_rendition(600) == (240, 400)
189    assert 2_800 * 6 / 8 == 2_100                                       # KB per 720p segment
190
191    # multi-CDN failover
192    assert route({"cdn_a": False, "cdn_b": True}, ["cdn_a", "cdn_b"]) == "cdn_b"
193    assert route({"cdn_a": False, "cdn_b": False}, ["cdn_a", "cdn_b"]) == "origin"
194
195    # Level 4: a public account page leaks between users
196    who = {"user": "asha"}
197    leaky = Edge(lambda url: buggy_account_page(who["user"]))
198    leaky.get("https://b.example/account", now=0)                       # Asha loads it first
199    who["user"] = "ravi"
200    body, status = leaky.get("https://b.example/account", now=5)       # Ravi gets Asha's page
201    assert status == "HIT" and "asha" in body
202    safe = Edge(lambda url: fixed_account_page(who["user"]))
203    safe.get("https://b.example/account", now=0)
204    who["user"] = "asha"
205    body, status = safe.get("https://b.example/account", now=5)
206    assert status == "MISS" and "asha" in body
207
208    return {"origin_load": (500, 100), "keys": (50, 1), "segments": 200}
209
210
211if __name__ == "__main__":
212    print("All checks pass.", run_checks())