A user-generated storytelling platform is 98% reads with an extremely skewed popularity distribution. The team debates caching, read replicas and denormalisation. How should the trade-off be framed?
Show the full answer Hide the answer
Framing the trade-off properly
The instinct is to compare the three options on performance. That is the least useful axis, because all three improve read latency. The differences are in what each one costs you when it goes wrong, and that is the comparison that should decide it.
| Option | Buys | Costs | Fails as |
|---|---|---|---|
| Cache | Largest latency win on hot content, cheapest | Staleness, invalidation complexity, a stampede risk | A thundering herd onto the database when it empties |
| Read replicas | Transparent to application code, no staleness logic | Replication lag, read-your-own-writes anomalies, linear cost | A user not seeing the chapter they just published |
| Denormalisation | Fastest reads, no runtime dependency | Write amplification, consistency burden moves into your code | Divergent copies nobody notices for weeks |
What the workload actually argues for
Extreme popularity skew is the deciding fact. With a small fraction of content serving most of the traffic, a cache is disproportionately effective — a small hot set gives a very high hit rate for very little memory, which is not true of a uniform workload where you pay for capacity you rarely hit.
Skew also creates the specific danger: the hot key. One extremely popular story concentrates load on one cache node and one database partition, and the fix is not more capacity but hot-key replication, request coalescing, and serving stale-while-revalidate so a single expiry does not release thousands of simultaneous origin requests.
The trade-off nobody states
Every one of these options trades consistency for latency, and the right question is not which is fastest but how stale is acceptable, for which content, to whom. A published chapter that the author cannot see for thirty seconds is a support ticket. A view count that lags five minutes is invisible. Choosing one staleness policy for both is how systems end up either too slow or embarrassing.