The Last CachebenderBook Five · War
Book Five · War
Book Five · War · Lesson 14 of 14
Lesson Fourteen

The Final Battle

Technique unlocked The Convergence all four realms in one design

The task

Design the complete caching strategy for the storefront, across every realm.

Bring together the techniques from the earlier lessons to design one complete caching strategy.

The rubric

#RequirementFrom
1Every one of the seven parts assigned to a realm — or marked never cached, with a reasonL1–L7
2A cache key and a TTL for each cached partL2, L10
3A read strategy and a write strategy for the application layerL8, L9
4An invalidation path for every mutable part, across every realm that holds itL11
5A named defense for each of the five attacksL12
6An instrumentation plan — what you measure, what alerts youL13
7A stated failure mode: what happens when the cache diesL6, L13

A worked example

Here is a worked example for the price, covering each requirement. Use the same structure for the other six parts.

Element: Price

1. Realms — Browser, CDN and Redis, with a 5-second local cache for the most popular products.

2. Keys and TTLs

RealmKeyTTLWhy
BrowserURL + currency + customer tiermax-age=10, must-revalidateA browser cannot be purged, so 10 seconds caps reuse without revalidation
CDNURL + currency + customer tier300s, purged on price changeA purge updates shared copies promptly; alert if it fails
Redisprice:{id}:{currency}:{tier}300s + jitterJitter prevents avalanche (L10)
Local cacheprice:{id}:{currency}:{tier}5sAbsorbs hot-key traffic before it reaches Redis

Currency and tier appear in every key that has a key at all. They change the answer, so they are in the key (L2).

3. Read and write

  • Read: validate the ID, check local memory and Redis, then apply the Bloom-filter check on a miss before the database lookup. Use single-flight to combine concurrent requests for the same price key (L8, L12).
  • Write: write-around — update the database, delete the cached copy (L9)
  • Invalidate after the database update: this avoids the write-ordering problem, though concurrent reads still need protection (L11)

4. Invalidation path

Admin changes price
    ↓
Database updated                                    immediate
    ↓
Local caches invalidate affected price keys          immediate
    ↓
Redis invalidates affected price keys                immediate
    ↓
CDN purges affected product responses                monitor completion
    ↓
Browser: no direct mechanism — bounded by its TTL    up to 10s

The browser reuse limit is 10 seconds. Staleness across the system also depends on successful invalidation delivery and CDN purges, so monitor both.

5. Attack defenses

AttackDefense
StampedeSingle-flight + refresh-ahead on top-100 products (L8)
PenetrationID validation, a current product-ID Bloom filter, and 60-second negative caching for confirmed misses; rate-limit requests (L12)
AvalancheTTL jitter on every price key (L10)
Hot key5-second local cache in front of Redis for top products (L5)
PoisoningCurrency and tier in the key; public is safe only because price is not per-user (L2, L12)

Bloom-filter policy: use the Lesson 12 filter to check product IDs, not prices or stock. A possible match still needs the normal lookup, and price cache keys must still include currency and tier. Before publishing a new product, add its ID to every filter used for rejection and clear any negative cache entry. If coverage is uncertain, bypass the filter.

6. Instrumentation

  • Hit ratio for the price: prefix specifically — not the global number (L13)
  • p99 latency on price lookups; alert if it exceeds 100ms
  • Track Bloom-filter rejections, bypasses, update failures and capacity; compare possible matches with database misses to spot wasted lookups
  • Alert on stale-price reports with Age attached, to identify the realm
  • Track invalidation-event and CDN-purge failures — either can leave a stale price in place

7. Failure mode

If Redis is unavailable, bypass its cache and any Bloom filter it hosts. Keep rate limits and database concurrency limits active so fallback traffic cannot grow without bound; return a temporary error when capacity is exhausted. Filter failures and database errors must never become “product not found” responses. For this example, assume the database can handle four times its usual load. Verify that assumption with a staging load test.

Do the other six

Product details. Product images. The asset bundle. Stock count. Reviews.

For this storefront, leave the cart badge response uncached to keep the policy simple. It belongs to one user and must never be reused as another user's answer. Cart data stored in Redis under a user-specific key is a separate decision.

The cart has needed a separate policy throughout the course. Requirement 1 is satisfied by explaining precisely why it is not shared.

The final assessment

When you can produce that document for a real system — and defend every TTL in it — you have finished this course.

The test is not whether you can list caching techniques. It is whether you can look at a piece of data and say: this belongs here, for this long, invalidated this way, and here is what happens when it goes wrong.

The end

The Surge arrives.

It arrives at the browser cache, and most of it stops there — never reaching the network at all.

What continues arrives at the edge, spread across the world, and is answered locally by copies already waiting.

What continues past that arrives at the application, and finds its answers in memory. The keys that are hot are already held close. The values approaching expiry have already been refreshed. The thousand requests that arrive for one missing key send one query and share its answer.

What reaches the database is a trickle. The database, which has been quietly caching all along, does not even notice.

And the Latency Lord, who built five weapons out of your own timers and your own keys, watches his attacks meet defenses you built throughout the course.

No single technique defeated him.

He was defeated by someone who had measured first.