CDN Optimization Techniques - Performance at Scale

LESSON

Caching, Workers, and Performance

024 30 min intermediate

CDN Optimization Techniques - Performance at Scale

By the end of this lesson, you will be able to...

  • Choose a CDN metric that corresponds to a specific user or origin bottleneck.

  • Trace how key normalization and a shield layer change the cost of a campaign-time cache miss.

  • Reject an apparent hit-rate improvement when it fragments a cache, hides an unsafe response, or leaves the expensive origin path unchanged.

Idea in one sentence: CDN optimization works when it makes the right reusable response cheap to serve and the remaining misses cheap to refill—not when it merely raises one aggregate cache number.

Core Insight

For Atlas Shop, a global campaign launches. The CDN dashboard reports an encouraging 94% object hit ratio. Yet the catalog origin's CPU remains high, p99 page latency is poor, and the rendered homepage is still the most expensive route.

The first explanation is simple: 94% is high, so caching must be working. It would be a good conclusion if the 94% represented the costly responses. But the hit ratio is dominated by tiny icons and a long-lived logo. The public homepage, which triggers an expensive render on a miss, is fragmented by tracking query strings and an unnecessary device header. It misses often enough to keep the origin busy.

The correction is to optimize a request path, not a dashboard total. Ask which responses consume origin work, bytes, or tail latency; make only truly equivalent requests share one cache key; then arrange refill so many outer-edge misses do not become many origin fetches.

The Production Symptom: A Good Percentage and a Bad Page

The team examines one minute of illustrative campaign traffic:

Request class Requests Edge hits Origin work per miss User consequence
/assets/logo.svg 80,000 99.9% tiny file read Almost no effect on page p99.
/assets/app.8f3.js 15,000 99.5% small asset fetch Healthy reuse.
/home?utm_source=... 5,000 45% 180 ms render + catalog reads Dominates origin CPU and p99.

The aggregate number is excellent because the first two rows are numerous. The operational pressure is in the last row. A cache metric becomes useful only when it is broken down by route or object class and paired with origin cost and user latency.

The page has two public representations, Spanish and English. But utm_source, utm_campaign, and a device header that does not change the HTML have been included in its cache key. The cache stores many copies that are semantically identical:

home | es | utm=mail | device=A  -> same HTML
home | es | utm=social | device=B -> same HTML

That is not safe personalization. It is accidental fragmentation.

The Initial Model: Increase TTL Until Hits Rise

Longer freshness can reduce misses, so increasing the TTL is a reasonable first lever when a public response changes rarely and a named stale window is acceptable. It works in that narrow setting.

It fails as a general optimization rule. A longer TTL does not merge duplicate keys. It does not make a personalized response shareable. It does not protect an origin from a sudden purge. And it may hide a product freshness requirement by serving an old response for longer.

The parallel mistake is to add every request field to the key “for safety.” That prevents an incorrect shared hit, but it also treats every harmless difference as a different object. Good key design is neither maximal sharing nor maximal separation. It names exactly the dimensions that change the representation.

The Better Model: Optimize the Bottleneck, Then the Miss Path

In plain English, ask two questions in order:

  1. Which route or object class makes users slow or makes origin expensive?
  2. When that class misses, how many requests and bytes reach origin before a warm copy exists again?

In this scenario, the homepage's language changes its text, so language belongs in the key. Tracking parameters do not change the public HTML, so they can be normalized away before cache lookup if analytics preserves them elsewhere. The device header belongs only if the origin actually emits a different representation because of it.

The technical mechanisms are key normalization, tiered caching or shielding, and request coalescing.

Cloudflare's cache-key documentation makes the relevant boundary explicit: cache configuration includes a cache key and purge modes that must match it. Cloudflare cache-key documentation. CloudFront documents Origin Shield as an additional cache layer that can consolidate same-object origin requests, while also adding cost and being a poor fit for some low-cacheability or proxy-only traffic. AWS Origin Shield documentation.

These provider examples support a general lesson, not a one-size-fits-all configuration: a second layer is valuable only when enough requests can safely reuse the same object to offset its extra hop, cost, and operational complexity.

A Worked Trace: Make a Homepage Miss Bounded

First, change the public homepage key:

before: home | language | device-header | all query parameters
after:  home | language

The after key is safe only under an explicit assumption: the HTML does not vary by device header or tracking parameters. Verify that assumption with origin output tests before deployment. If the page truly varies by an input, keep that input as a bounded key dimension or choose a different response boundary.

Now trace a Spanish campaign request after a purge. The timestamps are illustrative.

Step Outer edge Shield / upper tier Origin Result
1 Request home|es misses after a purge. Also misses; begins one fetch. Receives one render request. First reader waits for the fill.
2 Twenty other edges miss home|es. Sees the same in-flight fill. Does not receive twenty more equivalent renders. Followers are coalesced or receive the cached fill once ready.
3 Origin returns the Spanish public HTML. Stores the object. Render completes once. Outer edges receive and store the same result.
4 Later Spanish request with another utm_source. Not involved. Not involved. Normalized key hits at the nearby edge.

Before normalization, those twenty edges might have used several equivalent keys, making a shield less effective because it sees several different objects. Before coalescing, even a well-chosen key can produce duplicate work when requests arrive concurrently. Optimization is therefore a chain: correct key, cacheable response, bounded refill, then measurement.

So far, the plan has made a costly public homepage more reusable and protected its source on a miss. It has not made the cache safe for a signed-in basket, proved that the origin is now fast, or eliminated the need for purge and revalidation policies.

What to Measure Before Calling It Better

Compare the same request class before and after, under a representative campaign slice. Use a baseline; do not call a quiet five-minute period an optimization result.

Question Evidence
Did reusable homepages share safely? Key cardinality by language, response-version samples, wrong-language reports.
Did the expensive path reach origin less often? Homepage origin render count, origin CPU, and shield/outer cache status.
Did misses become less explosive? Concurrent same-key fetches, shield hit rate, post-purge origin peak.
Did users improve? Homepage p50/p95/p99 and error rate by region.
Did bytes improve where bytes are the cost? Compressed response size and byte hit ratio by object class.

Compression belongs in this same evidence loop. Compressing a large public text response can reduce transferred bytes even when the number of objects is unchanged. It costs CPU somewhere in the delivery path and may not help already-compressed images. Measure response sizes and CPU, rather than enabling compression as a universal slogan.

Trade-offs and Limits

This optimization improves reuse and origin protection for public homepages. It costs a more explicit cache contract, extra routing or shield configuration, observability work, and potentially an additional service charge or hop.

The trade-off is situated:

This does not solve a slow database query inside every remaining origin miss. It only makes repeated work less likely to reach that query. The next lesson uses profiling to inspect the origin path once the request-level evidence has identified that it is still worth investigating.

The boundary signal is a mismatch between the intended mechanism and the evidence: a higher aggregate hit ratio with unchanged homepage p99, a shield layer with little reuse, a sudden rise in key cardinality, or a cache hit that serves the wrong representation. Treat each as a reason to revisit the response contract, not as a prompt to add more arbitrary knobs.

Check: A key-normalization change raises the homepage hit ratio from 45% to 88%, but some French visitors now receive Spanish text. Did the change succeed?

Think first, then reveal.

Answer: No. The change merged requests that were not equivalent. The response correctness failure outweighs the hit-rate gain. Restore language as a key dimension, verify output by variant, and then measure reuse inside each safe language population.

Practice: Choose the Next Lever

The campaign has these observations:

Propose the smallest next optimization. Name one key change, one miss-path control, one metric that should fall, and one correctness check that must remain green.

A good answer should mention:

Connections

The previous lesson made purge a transition problem: correctness and refill stability must both hold. This lesson reduces the cost of that transition by shaping reusable keys and consolidating duplicate fills. The next lesson moves inside the origin process: when a measured miss still dominates, a profile can show whether CPU, allocation, locks, or waiting are responsible.

Resources

Key Takeaways

PREVIOUS Cache Purging Strategies - CDN Cache Invalidation NEXT Performance Profiling - Finding Bottlenecks