Measuring cache effectiveness, and designing a strategy end to end
Every earlier lesson covered one specific mechanism in isolation. This closing lesson is about the actual workflow: starting from a real performance problem, measuring whether a cache is the right answer, and choosing — deliberately, from everything this domain covered — exactly which mechanisms a specific feature actually needs.
Advanced
3 min read
The metric that answers "is this cache actually helping": hit ratio
Hit ratio = cache hits / (cache hits + cache misses)
A cache's hit ratio is the single most important number for judging whether it's earning its complexity. A hit ratio near 95% means the cache is absorbing nearly all read load from the database — exactly the intended effect. A hit ratio near 10% means almost every read still reaches the database anyway, and the cache is adding real operational complexity (another system to run, invalidate correctly, and reason about during an incident) for very little actual benefit — a strong signal to revisit the TTL, the eviction policy, or whether this data should be cached at all (lesson 11).
Sizing a cache: how big is actually enough
A cache too small for its working set evicts entries faster than they're naturally re-requested, producing a low hit ratio no matter how well-tuned the eviction policy (lesson 3) is — there's simply not enough room to hold what's actually being accessed repeatedly. Sizing starts from the data, not a guess: estimate the working set (how much data is genuinely accessed repeatedly within a TTL window, not the total size of all data that could be cached) and size the cache to comfortably hold it, then watch the hit ratio in production to confirm the estimate was right rather than assuming it was.
Cost-benefit: caching isn't free even when it works
Every cache this domain has covered costs something beyond the obvious infrastructure: invalidation logic that must be kept correct as the codebase changes (lesson 11), a stampede risk that needs a deliberate mitigation (lesson 4), and — for a distributed cluster — consistent-hashing and rebalancing behavior (lesson 7) to actually understand. A cache that achieves a 40% hit ratio on cheap, fast-to-query data may genuinely cost more in ongoing complexity than it saves in database load — "does this pay for itself" is a real question, not a rhetorical one, and the hit ratio plus the query cost it's avoiding are exactly the two numbers needed to answer it honestly.
A worked design: caching a product page end to end
A product page reads product details (changes rarely), current stock count (changes often), and personalized recommendations (per-user, changes occasionally) — one page, three genuinely different caching needs:
Applying one uniform caching policy to all three fields — the naive, undifferentiated approach — either under-caches the stable product details (paying repeated database cost for data that almost never changes) or over-caches the volatile stock count (showing wrong availability to real customers). Treating each field according to its own actual read/write ratio, exactly the question lesson 11 raised, is what this entire domain has been building toward: caching isn't one decision made once per feature, it's a series of small, deliberate decisions made per piece of data, using whichever specific mechanism from this domain actually fits that data's real access pattern.