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())