Approach: split by volatility, personalization, and privacy. Put globally shareable, highly cacheable bytes at the CDN edge (static assets, public HTML fragments with low personalization). Keep per-user or sensitive fragments in the application or an edge compute layer (Edge Workers / Lambda@Edge) that can assemble personalized pieces.
Which layer for which content:
- CDN edge: static assets (JS/CSS/images), locale-agnostic marketing HTML, components that vary only by URL and headers (Accept-Language).
- Edge compute: lightly personalized fragments derived from non-sensitive headers (region, AB-test bucket), where you can run fast logic and still cache by derived keys.
- App / origin or signed cookies: per-user private data (account info, billing), sensitive personalization, or content requiring strong authorization.
Cache key strategies:
- Base keys on stable inputs that determine content: URL path, query-significance whitelist, Host, Accept-Language, A/B bucket header.
- Avoid including volatile inputs (Authorization, full cookies) in CDN keys. Instead, normalize: use derived tokens (signed short-lived cache keys) or separate fragment endpoints that accept a user-id hash.
- Example CDN key: cache_key = sha256(host + path + lang + ab_bucket)
- For edge-assembled pages, cache fragments with keys like fragment:{component}:{region}:{ab_bucket} and assemble server-side into final response.
Privacy concerns:
- Never cache user-identifiable sensitive responses at shared CDN caches. Use cache-control: private for responses containing PII.
- Scrub headers/cookies before sending to shared caches. If you must cache semi-sensitive data, encrypt or sign fragments and serve them via authenticated edge caches with per-client TLS/session binding.
- Audit logs and TTLs: shorter TTLs for anything close to sensitive; expire on permission changes.
Stale-while-revalidate (SWR) approaches:
- Use Cache-Control: public, max-age=short, stale-while-revalidate=long for non-sensitive assets so users get fast responses while origin refresh happens in background.
- For personalized fragments, combine SWR with background revalidation at edge or origin: serve stale fragment while asynchronously fetching a fresh one; if freshness matters, add revalidation triggers on user interaction.
- Use conditional requests (ETag/If-None-Match) to minimize origin cost during revalidation.
Trade-offs and operational notes:
- More aggressive edge caching reduces latency and origin load but increases risk of serving stale or incorrect personalized content.
- Prefer composition: cache as many generic fragments as possible and do personalization assembly close to the user.
- Monitor cache-hit ratio, tail latency, and error rates; implement feature flags to roll back caching changes safely.
This strategy balances performance, correctness, and privacy by placing content at the layer matching its personalization, sensitivity, and freshness requirements.