Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Every component in a distributed system is a trade, and the trade is never free. A cache buys latency and pays in staleness. A queue buys decoupling and pays in eventual, out-of-order, possibly duplicated delivery. A read replica buys read throughput and pays in replication lag, which means a user can write something and then not see it. A blob store buys effectively unlimited cheap bytes and pays by making those bytes unqueryable and expensive to move. If you can name the property a component buys but not the currency it charges, you do not understand the component — you have memorised its logo. Worse, the costs compound in ways that surprise people: a cache with a 90 percent hit rate silently becomes load-bearing infrastructure, because the day it dies your database gets ten times its normal traffic in a single second. That is not a caching problem; it is a capacity problem you created when you added the cache and did not write down what it cost.
Trace one request through the standard chain and, at every hop, say the two things: what it buys, what it charges. The diagram below is that chain. Read the second and third lines of every box — they are the part people skip.
Then do the arithmetic that makes the cache trade concrete. Assume a cache hit costs 1 ms and a database read costs 40 ms, the service takes 2,000 reads per second, and the database can sustain 400.
At a 90 percent hit rate the mean latency is 4.9 ms, which looks excellent. But the 99th percentile is still 40 ms, because at a 90 percent hit rate one request in ten misses and the 99th-percentile request is definitively a miss. A cache moves the mean long before it moves the tail. The tail only improves once the hit rate crosses 99 percent, and getting from 90 to 99 is far harder than getting from 0 to 90.
Now the part that ends up in postmortems. At a 90 percent hit rate the database sees 200 rps — half its capacity, comfortable. If the cache goes away, the database sees 2,000 rps instantly: a 10x jump to five times its capacity, which is not a slowdown but an outage. And the better your cache is, the worse this gets: at a 99 percent hit rate the database normally sees 20 rps, so cache loss is a 100x step change. The cost of a cache is not staleness. The cost of a cache is that you now have a component whose failure mode is a 100x traffic spike on the thing behind it.
Every box in the diagram has an equivalent second-order cost. A load balancer buys one address in front of many servers and charges you a new thing to operate, plus health-check semantics that decide what down means. A queue buys the right to accept work faster than you can do it, and charges you the entire class of bugs that begins with the words but the message arrived twice. A search index buys queries your database cannot answer, and charges you a second copy of your data that drifts from the first.
# cache_math.py — what a cache actually buys, and what it costs.
CACHE_MS, DB_MS = 1.0, 40.0
TOTAL_RPS = 2000.0 # reads arriving at the service
DB_CAPACITY_RPS = 400.0 # what the database can actually sustain
print(f"{'hit':>6} {'mean ms':>8} {'p99 ms':>7} {'db rps':>7} {'db load':>8}")
for h in (0.0, 0.50, 0.90, 0.95, 0.99, 0.999):
mean = h * CACHE_MS + (1 - h) * DB_MS
# the 99th-percentile request is a miss unless the hit rate exceeds 99%
p99 = CACHE_MS if h >= 0.99 else DB_MS
db_rps = TOTAL_RPS * (1 - h)
print(f"{h:>6.3f} {mean:>8.2f} {p99:>7.1f} {db_rps:>7.0f} "
f"{db_rps / DB_CAPACITY_RPS:>7.0%}")
print()
for h in (0.90, 0.99):
normal = TOTAL_RPS * (1 - h)
print(f"cache dies at hit rate {h:.0%}: db goes {normal:.0f} -> "
f"{TOTAL_RPS:.0f} rps ({1 / (1 - h):.0f}x step, "
f"{TOTAL_RPS / DB_CAPACITY_RPS:.1f}x over capacity)")
# Output:
# hit mean ms p99 ms db rps db load
# 0.000 40.00 40.0 2000 500%
# 0.500 20.50 40.0 1000 250%
# 0.900 4.90 40.0 200 50%
# 0.950 2.95 40.0 100 25%
# 0.990 1.39 1.0 20 5%
# 0.999 1.04 1.0 2 1%
#
# cache dies at hit rate 90%: db goes 200 -> 2000 rps (10x, 5.0x over)
# cache dies at hit rate 99%: db goes 20 -> 2000 rps (100x, 5.0x over)python3 main.py