Purge — URL, surrogate key, or sledgehammer
Purge is a write propagated to every POP; surrogate keys let one API call invalidate every related object atomically — without them you are either listing every URL by hand or nuking the whole cache.
Purge is the escape hatch you reached for at the end of the last scene — but purging a copy in one POP doesn't help the other 299 POPs still serving it, so the question becomes WHICH POPs and WHICH entries one purge call actually invalidates.
Scene 07
Purge — URL, surrogate key, or sledgehammer
- Watch
- Try it
- Predict
- Capture
A URL purge for /logo.png is fired from the Frankfurt ingress POP. Watch the wave ripple outward across all 12 POPs — only the /logo.png cell clears in each one. Origin RPS stays flat: each POP's next request will be a single miss.
Highlighted lines are the ones running in the diagram right now.
def purge_url(url):p = { kind: 'url', target: url }broadcast_purge(p) # one cell per POPdef purge_surrogate_key(tag):p = { kind: 'surrogate', target: tag }broadcast_purge(p) # every cell sharing tagdef purge_zone():p = { kind: 'zone', target: '*' }broadcast_purge(p) # every cell, every POP
def apply_purge(p):for cell in self.cache:if matches(cell, p):cell.invalidate() # next request = missack(p.id, self.pop_id)def matches(cell, p):if p.kind == 'zone': return Trueif p.kind == 'url': return cell.url == p.targetif p.kind == 'surrogate': return p.target in cell.tags
def broadcast_purge(p):p.id = new_purge_id()pending = set(all_pops)for pop in all_pops:pop.send(p) # bimodal multicast / gossipwhile pending:pop_id = wait_for_ack(p.id)pending.remove(pop_id)# p50 ~150 ms; p99 = slowest POP in the fleetreturn { p50: ack_p50(), p99: ack_p99() }
Where this sits in Build a CDN
Scene 07 of 13, in the Control act — Purge flavors, the cache key, and the Vary footgun.. Three purge flavors: URL (precise, slow at scale), surrogate-key (atomic, fast), zone-wide (sledgehammer that stampedes origin).
Up next. Purge invalidates entries — but what determines which entries are matches in the first place? The cache key, and the Vary header that quietly multiplies it.