Lesson 24 / 25

Case Study: Caching an E-Commerce Catalogue

Design a complete caching strategy for a high-traffic product catalogue.

Putting the layers together

A shop with 2 million products sees 30,000 requests per second at sale peaks, 95% of them reads. The design: static assets are fingerprinted and cached for a year at the CDN and in browsers. Product and category pages are rendered by the app and cached at the CDN with s-maxage=300, stale-while-revalidate=60 and stale-if-error=600, tagged with product, category and brand IDs. Product data is cached in Redis with cache-aside, versioned keys and a 10-minute TTL with jitter, plus a 1-second in-process L1 for the hottest keys. A change data capture stream from the products and prices tables deletes Redis keys and purges CDN tags on every committed change. Prices and stock shown on pages may be up to a few seconds stale, but checkout re-reads them from the database inside the order transaction. Search results for the top queries are micro-cached for 15 seconds. Monitoring tracks edge and Redis hit ratios, origin load, purge latency and evictions; load tests run warm and cold.

The design in one table

Each layer has an explicit freshness rule and invalidation path.

data                   where cached                 TTL / freshness             invalidation
---------------------  ---------------------------  --------------------------  -----------------------
JS/CSS/images          browser + CDN                1 year, immutable           new file name
product/category HTML  CDN                          s-maxage 300, swr 60        purge by tag via CDC
product JSON           Redis (+ 1 s local L1)       600 s +/- 10% jitter        delete key via CDC
price/stock on page    Redis                        <= 30 s                     delete key via CDC
price/stock at checkout  not cached                 always current              n/a (read DB in txn)
top search queries     CDN micro-cache              15 s, stale-if-error 300    TTL only
user cart/account      not shared-cached            private / no-store          n/a

Write the freshness contract down

The table above is the most useful artefact in a caching design. It tells product managers what staleness to expect and tells engineers where each invalidation must happen.

Quick check: In the case study, why does checkout read price and stock directly from the database?

  • Decisions that charge money or commit stock must use current data, even if pages show slightly stale values
  • Redis cannot store prices
  • CDNs block checkout pages
  • Databases are faster than Redis
Answer

Decisions that charge money or commit stock must use current data, even if pages show slightly stale values — Display may tolerate staleness; transactions must use the source of truth.