Caching tiers and cache placement
Browser, CDN edge, reverse proxies, distributed Redis, and DB buffer pools.
What you will learn
- Place caches along the request path, from the client to the database, and say what each tier holds.
- Compute effective latency from the hit ratio, and how the hit ratio changes database load.
- Size an application cache for its working set.
The memory hierarchy and the cost of disk I/O
Data access times span many orders of magnitude (chapter 2's latency numbers, from about 2012): a main memory reference takes about , a random 4 KB SSD read about , and a round trip within a datacenter about . Data held in RAM is much faster to reach than data on disk, which is why in-memory caches such as Memcached and Redis sit between applications and their databases.
Caching works because accesses are not uniform: recently used data tends to be used again, and popular items take a large share of requests. A cache in front of a database also absorbs uneven load: databases do best when reads and writes spread evenly across partitions, and popular items skew that distribution.
The caching hierarchy
Caches can sit at every stage of the request path:
| Tier | Where | Examples | What it typically holds |
|---|---|---|---|
| 1. Client | The OS or browser | HTTP cache (Cache-Control, ETag) |
Static files, recently fetched responses |
| 2. CDN | Edge locations near users | CloudFront | Static media and other cacheable responses |
| 3. Web server | Reverse proxy or web cache | NGINX, Varnish | Static and dynamic responses, without contacting the application servers |
| 4. Application cache | In-memory key-value stores between the app and its storage | Memcached, Redis | Sessions, fully rendered pages, activity streams, user graph data |
| 5. Database | The database's own memory | PostgreSQL shared buffers, InnoDB buffer pool | Recently used pages; usually some caching is on by default, and tuning it for your workload helps further |
Within the application cache you can cache at two levels: query results (hash the query as the key; hard to invalidate, because one changed cell can affect many cached queries) or objects (assemble the data into an object and cache that; remove it when its underlying data changes). Avoid file-based caching, which makes cloning and autoscaling servers harder.
Cache hit ratio mathematics: The effective latency equation
The performance of any cached system is strictly governed by its Hit Ratio ():
The Effective Average Latency () experienced by clients is:
Why 95% vs. 99% hit ratio matters
Consider a system where and :
- At : (Database absorbs 20% of traffic).
- At : (Database absorbs 5% of traffic).
- At : (Database absorbs only 1% of traffic).
A drop from to hit ratio multiplies database query load by ().
Working set estimation & sizing formula
The working set is the subset of data actively requested over a time window (e.g. 24 hours). Size the cache to hold it:
Assume, for illustration, that 20% of a catalog's items receive most of its reads (an 80/20 split; measure your own traffic to find the real share):
- Web & Mobile Shoppers: 1 × Clients & Users
- Anycast DNS / Route53: 2 × Anycast DNS / Route53
- CloudFront Edge POPs: 2 × CloudFront / CDN Edge
- API Gateway / LB: 3 × Application Load Balancer
- Product Catalog Workers: 4 × App Compute Server
- Redis Cache Cluster: 4 × Redis In-Memory Cache
- Primary DB / Buffer Pool: 2 × Primary Relational DB
- Web & Mobile Shoppers sends requests to Anycast DNS / Route53
- Anycast DNS / Route53 sends requests to CloudFront Edge POPs
- Anycast DNS / Route53 sends requests to API Gateway / LB
- CloudFront Edge POPs sends requests to API Gateway / LB
- API Gateway / LB sends requests to Product Catalog Workers
- Product Catalog Workers sends requests to Redis Cache Cluster
- Redis Cache Cluster sends requests to Primary DB / Buffer Pool
- Product Catalog Workers sends requests to Primary DB / Buffer Pool
Key takeaways
- Caching works because accesses are skewed: recent and popular items take most requests.
- Cache objects rather than query results where you can: an object is easy to invalidate when its data changes.
- ; falling from 99% to 95% hits sends five times the queries to the database.
- Size RAM as working-set keys × item size × (1 + overhead), using the share of items your own traffic shows to be hot.
Sources
- System Design Primer: Cache (client, CDN, web server, database, application caching)
- System Design Primer: Latency numbers every programmer should know
Adapted from The System Design Primer by Donne Martin, licensed under CC BY 4.0. Changes were made.