Multi-Layer Cache Architecture: From CDN to Database
Cache layers in high-traffic systems: CDN, local (Caffeine) and distributed (Redis) caches, invalidation strategies, cache stampede defense and hit-ratio management.
Why is caching an architectural decision, not a tuning knob?
In a high-traffic system, a cache is not an accelerator bolted on at the end; it is an architectural layer that decides which data lives where, for how long, and under which consistency promise. A badly built cache strikes in two ways: business errors from stale data, or a stampede onto the database when keys expire en masse. This article puts the layers, patterns and defenses on one map.
The layer map: where does each kind of data live?
Layer | Typical content | Latency | Consistency character |
|---|---|---|---|
CDN / edge | Static assets, anonymous pages/fragments | ~ms (closest to the user) | TTL + deliberate purge |
Local (in-process, Caffeine) | Hot small dictionaries, configuration | ~µs | Per-node; short TTL is mandatory |
Distributed (Redis) | Sessions, computed views, hot objects | ~ms | Shared; invalidation manageable |
Database buffer | Frequently accessed page/index blocks | — | The engine's job; fed by good queries |
The principle is simple: the closer to the user a request is absorbed, the cheaper the system scales. A request absorbed at the CDN never reaches the application; absorbed locally, it never reaches Redis; absorbed in Redis, it never reaches the database — capacity plans are built on those absorption rates.
Access patterns: cache-aside and its relatives
The most common pattern is cache-aside: the application checks the cache first, reads from the source on a miss and writes back — control stays in the application, flexibility is high; the price is the cost of first requests and fill races. Read-through/write-through hides reads and writes behind the cache layer; the consistency promise sharpens, the dependency grows. Write-behind buffers writes and flushes in batches — buying write throughput, paying with data risk on power loss and ordering complexity. The enterprise default is cache-aside + event-based invalidation; the others are chosen by measured need.
Invalidation: the hardest problem, three working strategies
First, TTL: every key has a lifetime; simple and robust, at the cost of staleness up to the TTL window. Second, event-based invalidation: an event published on data change deletes the affected keys — freshness gained, but it demands a "which change touches which keys" map, and TTL remains the safety net for missed events. Third, versioned keys: when content changes, the key changes (e.g. price-list v42); old keys are not deleted, they die — versioned URLs instead of CDN purge are exactly this pattern. The practical recipe: TTL always + event-driven deletes on critical data + versioned keys for immutable content.
Cache stampede: defending against the herd
When a popular key expires, hundreds of concurrent requests hit the source at once — the stampede (dogpile/thundering herd), the classic cause of campaign-day database collapse. Defense is layered: a single-fill lock (one request per key goes to the source; the rest briefly wait or are served the stale value); TTL jitter (random skew added to lifetimes so keys do not die together); early refresh (hot keys nearing expiry are refreshed in the background); and a negative cache ('not found' answers stored with short TTLs so queries for non-existent records stop punishing the source). These four mechanisms are the standard equipment of a high-traffic cache.
Hit ratio is a budget
A cache rots where it is not watched: hit ratio, eviction counts and memory per region belong on a dashboard. The three classic causes of a falling hit ratio: needless key diversity (the same data stored under different keys), TTLs shorter than the business actually needs, and undersized memory producing eviction storms. The decision rule: every cache region has a written target hit ratio; dropping below it triggers an alert and a root-cause analysis.
Business impact: the cheapest capacity is the request that never arrives
The return on cache investment reads directly off the infrastructure bill: traffic absorbed at the CDN and Redis keeps the database and application tiers small; lower p95 latency shows up in conversion. In campaign scenarios the difference becomes dramatic — a correctly layered cache serves most of peak traffic without it ever reaching the source. The cost-efficient answer to "can you handle this many concurrent users?" is absorption rate, not machines.
Frequently asked questions
Should local cache and Redis be combined?
For hot, small data, yes (two-level caching): the local layer gives microsecond access, Redis provides sharing and invalidation. Short TTLs on local copies bound the cross-node inconsistency window.
Why is caching everything wrong?
Rarely read data produces no hits, occupies memory and creates eviction pressure; personalized data carries leak risk under wrong keying. Caches are built on measured hot data.
Can personal data be cached?
When necessary — with per-user keying, encryption/restricted access, and TTLs aligned with KVKK/GDPR retention. Storing personal data under a shared key is the classic leak mistake.
Is stampede protection built into frameworks?
Caffeine's loading-cache behavior provides it in-process; in the distributed layer, the lock/early-refresh mechanics are the application's responsibility, built with library support.
Cache architecture checklist
Layer map produced: which data lives in CDN/local/Redis
Default pattern is cache-aside; exceptions justified
TTL on every key; event-based invalidation on critical data
TTL jitter and single-fill locks active
Negative caching and early refresh on hot keys
Hit/eviction dashboards and target ratios defined
Keys holding personal data inventoried; TTLs aligned with KVKK/GDPR
SSH Yazılım designs cache architectures and builds stampede resilience for high-traffic systems end to end. Let us raise your absorption rate together.