Last year I watched a client push a critical pricing update that hit their origin in Ashburn instantly but took 47 seconds to appear in Singapore. Their support queue exploded with customers seeing two different prices for the same SKU in different regions, and their checkout service couldn't decide which price was authoritative. That's not a simple caching bug, that's a consistency model problem. If you're running global CDN Content Lifecycle Management: From Upload to Expiration and Archival without understanding which model you're actually using for content replication, you're gambling with your user experience.
How Content Replication Really Moves Across the Edge
Most engineers I've worked with assume CDN replication is magic - you purge a URL and it disappears everywhere. It doesn't. In a modern tiered architecture, your content replication path looks more like origin -> origin shield -> regional parents -> edge PoPs -> browser cache. Each hop introduces its own queuing, validation, and propagation delay. I've debugged systems where a purge request spent 800ms just waiting in a shield node's message queue during peak traffic, long before it even started fanning out to 300+ edge locations. That hierarchy is why a purge that claims to be "global in 150ms" in marketing slides rarely holds up under real load.
There are two fundamental ways that replication happens, and most large CDNs use a hybrid of both. Pull-based replication is lazy: an edge node only fetches a new version when its cached copy expires or is invalidated and the next user request arrives. Push-based replication is eager: the control plane actively broadcasts invalidations or new objects to all nodes. Pull is cheap and scales beautifully, but it guarantees divergence between nodes until TTLs expire. Push is faster but expensive and fragile at scale. Your choice here directly dictates which consistency models you can even offer. If you're still relying on short TTLs to paper over replication lag, you haven't solved consistency, you've just made your origin pay for it.
The mechanics matter because they define your consistency window. With pure pull, your HTTP Working Group Specifications cache directives like Cache-Control and CDN-Cache-Control are your only replication contract. With push, you're dependent on the control plane's delivery semantics - at-least-once, ordered, durable. We've seen outages where a provider's purge queue silently dropped messages for 12 minutes while returning 200 OK to the API caller. Don't trust the status code, verify convergence with real edge probes.
# Edge replication validation - don't trust the purge API response
# Check actual convergence across PoPs after an invalidation
curl -s -H "Fastly-Debug:1" -H "Pragma: no-cache" \
https://www.example.com/api/pricing.json | grep -i "x-cache"
# Expected after purge: MISS on shield, MISS on edge
# Poll multiple PoPs via test nodes or synthetic checks
for POP in iad lax sin nrt fra; do
echo -n "$POP: "
curl -s -H "X-Debug-PoP: $POP" \
https://www.example.com/api/pricing.json | jq .version
done
# Response headers to enforce pull-based replication contract
HTTP/1.1 200 OK
Cache-Control: public, max-age=60, stale-while-revalidate=30
CDN-Cache-Control: public, max-age=300
Surrogate-Key: product-12345 pricing/v2
ETag: "v2.4.1-9f3a"
Eventual Consistency: The Default You Didn't Explicitly Choose
Here's the uncomfortable truth: if you haven't specifically engineered for something stronger, your CDN replication is eventually consistent. That means after a write to origin, there is an unbounded (but hopefully short) period where different edge nodes will serve different versions. For most static assets - images, JS bundles, marketing pages - that's perfectly fine. I tell teams that eventual consistency is the right default for about 80% of their content. The trouble starts when they treat dynamic or transactional content with the same model and act surprised when users see stale data.
The appeal is performance and availability. Eventual consistency lets every PoP serve from local cache without coordinating with any other node or even the origin. Reads are blazing fast because there's no global lock or quorum check. Writes propagate in the background, usually via an eventually delivered invalidation event. According to guidance in web.dev Articles on stale-while-revalidate, you can even hide much of this lag by serving stale content while fetching a fresh copy asynchronously. That pattern is brilliant for performance, but it explicitly trades recency for speed. Your users in London and Tokyo will converge eventually, but "eventually" could be 2 seconds or 2 minutes depending on your CDN Content Expiration Policies: Setting Freshness Rules That Match Content Dynamics, network partitions, and queue depth.
I once spent a week chasing a bug where users were seeing yesterday's feature flags after a deploy. The CDN was doing its job - serving cached JSON with a 5-minute TTL. The deployment system was doing its job - pushing new code to origin. No one had built the bridge between them. We fixed it not by lowering TTLs to 5 seconds (which would have tripled origin load) but by adopting versioned URLs and surrogate key purging so the content replication became atomic for that flag file. Eventual consistency wasn't broken, our expectations were.
// Origin response for eventually consistent API payload
// Clients tolerate short staleness for speed
app.get('/api/config.json', (req, res) => {
// Allow edge to serve stale for 60s while revalidating
// This keeps p95 TTFB low while still converging
res.set({
'Cache-Control': 'public, max-age=30, stale-while-revalidate=60, stale-if-error=86400',
'Surrogate-Control': 'max-age=300',
'Surrogate-Key': 'config global',
'ETag': `W/"${configVersion}"`,
'Vary': 'Accept-Encoding'
});
res.json(currentConfig);
});
// Purge is best-effort and propagates lazily
// POST /service/:id/purge/config -> 200 OK but convergence is async
await cdn.purgeBySurrogateKey('config');
// Verify with version polling, don't assume immediate global consistency
Strong and Causal Consistency: When "Eventually" Isn't Good Enough
Strong consistency promises that after a write completes, every subsequent read from any edge node will see that write. It's the model you want for things like authenticated API responses, inventory counts, or access control lists where seeing stale data isn't just annoying, it's incorrect or unsafe. Achieving it on a CDN isn't impossible, but I'd argue you shouldn't try to do it with cache alone. True strong consistency requires coordination - typically a global invalidation barrier, versioned reads against origin, or request coalescing through a shield with strong read-after-write guarantees. That coordination adds latency. Every read might need to check a global version counter or revalidate with origin, which can add 80-250ms to your p95, and it reduces availability during partitions.
Causal consistency sits in the middle and it's the model most teams actually need but don't know to ask for. It guarantees that if operation B causally depends on operation A (like a comment that replies to a post), everyone will see A before B. It doesn't guarantee everyone sees the latest write instantly, but it preserves order where it matters. For features like social feeds, collaborative docs, or multi-step checkout flows, this prevents the weirdness where a user sees a reply before the original message. Implementing it usually means attaching vector clocks or version dependencies to your purges. Fastly's surrogate keys and Cloudflare's Cache-Tag with ordered purges are practical attempts at this - you purge post:123 and comment:456 together and the CDN ensures the dependency order is respected at each PoP.
Choosing between these models isn't a theoretical exercise. It's a direct trade-off between latency, cost, and correctness. Before you push for strong consistency everywhere, audit your content. For Content Versioning Patterns for CDN: Atomic Deploys and Rollback-Ready Assets, immutable versioned assets give you strong consistency for free without any coordination cost. Save the expensive coordination for the small slice of mutable, user-specific data where staleness truly breaks your product.
| Consistency Model | Convergence Window (p95) | Read Latency Overhead vs. Cache HIT | Origin Load Impact | Best Fit |
|---|---|---|---|---|
| Eventual Consistency | Implementing Consistency Controls Without Killing Your Hit Ratio
Here’s where theory hits the edge config. You don’t just flip a switch to “strong consistency” — you engineer it with TTLs, validation, and invalidation, and you pay for it in origin load every single time. Most teams we see get this wrong by setting a global 1-year The practical middle ground is tiering your content by mutability, not just file type. Static, versioned assets (think For anything requiring causal or strong consistency — like authenticated user state or inventory counts — don’t cache it at the edge at all, or use a 1-5 second TTL with edge validation against origin. You’ll take a hit ratio drop of 15-25% on that route, but your 99th percentile staleness window drops from minutes to under 2 seconds. Combine that with an origin shield in one region and you’ve centralized the read-after-write check without hammering origin from 300+ POPs.
Advanced Patterns and Fixing Consistency Drift in ProductionWhen you’re federating multiple origins or running active-active in several regions, simple purge isn’t enough. You’ve got to deal with replication lag between origins before the CDN even sees the change. We’ve debugged outages where the CDN purged perfectly in 200ms, but the origin database replica in eu-west-1 was still 7 seconds behind us-east-1, so edges refetched… stale data. If you’re in that world, you need CDN Content Federation: Aggregating Content from Multiple Origins into Unified Delivery with a version vector or timestamp authority. Don’t let each origin claim it’s the source of truth — elect one primary for writes and have edges validate against a global The other killer is the thundering herd on invalidation. You purge a popular key that gets 20k RPS, every edge misses at once, and origin melts. We’ve seen this take down origins that handle 500 RPS normally when hit with 40k concurrent revalidations. Fix it with request coalescing (aka collapsed forwarding) at the shield — only one request goes to origin per key per POP — plus a soft-purge that serves stale while revalidating. Fastly, Akamai, and CloudFront all support this now, but it’s disabled by default. Turn it on. For truly multi-region active datasets, look at Multi-Region Content Synchronization: Keeping CDN Edges in Agreement patterns like lease-based coherence or CRDTs for counters, which let you keep a 95%+ hit ratio while keeping drift under 1 second. Troubleshooting tip: instrument everything. You can’t fix what you can’t see. Add Frequently Asked QuestionsWe use surrogate key purging — why are users still seeing stale content for minutes?Two common culprits: browser cache and non-compliant downstream caches. Your edge purge doesn’t clear a user’s local browser cache if you sent Does strong consistency mean we can’t cache at all?Not necessarily, but you’re trading hit ratio for correctness. You can achieve strong read-after-write by caching for only 1-2 seconds with How fast is “eventual” really for major CDNs?For modern pull-based CDNs, global purge propagation is fast but not instant. Expect 150-400ms for Fastly/Cloudflare/Akamai to invalidate in 90%+ of POPs, with p99 around 1.5-3 seconds due to long-tail nodes. Full convergence — including shield refetch — is usually 2-5 seconds. If you need sub-second guarantees globally, you need short TTLs plus active validation, not just purge. Measure it yourself: publish a unique version header and poll 20 edge POPs via Catchpoint or similar. Should we use stale-while-revalidate for pricing or inventory data?Only with a very short staleness window and clear business approval. Serving a $49 price as stale for 60 seconds while you revalidate might be okay; serving “in stock” for 60 seconds when you’re actually sold out isn’t. For critical inventory, use External ReferencesRelated Articles
References & Standards: HTTP Working Group Specifications · web.dev Articles · IETF Datatracker |