Module 09 · Lesson 02

Seven anti-patterns that quietly cost a fortune

None of these are bugs. All of them multiply traffic, latency or storage until the bill arrives.

Advanced 8 min read Updated 2026-11-02

What you will be able to do

  • Recognise chatty and over-fetching interfaces from their symptoms
  • Bound fan-out and parallelise independent calls
  • Explain why synchronous chains amplify tail latency
  • Identify hot keys and retention leaks before they become incidents

1-2. Chattiness and synchronous chains

A chatty interface makes many small calls where one would do. The per-call cost is not the work, it is the network and serialisation. At 0.5 ms per same-region call, 400 calls is 200 ms before any real work happens.

Sequential chains are the same problem with a tail-risk bonus. If five independent calls each have a p99 of 100 ms, running them sequentially gives a p99 near 500 ms; in parallel, near the slowest one. The fix is structural: identify independent calls, run them concurrently with a shared deadline, and keep the dependent ones in order.

sequential:  60 + 60 + 60 + 60 + 60 = 300 ms p50, tails add
parallel:    max(60, 60, 60, 60, 60) = ~60-80 ms p50, one tail
Parallelism needs a deadline
Firing eight calls concurrently with no shared timeout turns a slow dependency into a hung request. Pass one deadline down and cancel the rest when it expires.

3. Unbounded fan-out

A user with two million followers posts. Fan-out on write creates two million timeline entries; fan-out on read queries two million followees. Neither is acceptable as stated, which is why real systems use a hybrid: fan-out on write for normal accounts, pull-on-read for very large accounts, merged at request time.

ApproachWritesReadsBreaks at
Fan-out on writeExpensive, proportional to followersCheap, precomputedCelebrity accounts
Fan-out on readCheapExpensive, merge many sourcesHeavy readers
HybridCheap for celebritiesMerge push and pullComplexity

4. Over-fetching

  • **SELECT \* on a wide table** pulls blobs you never render. Select columns, or split large fields into their own table.
  • Fetching a list to show a count does the work of a full scan. Use a count query or a maintained counter.
  • Returning full objects to mobile clients costs bandwidth and parse time. Return what the screen needs.
  • Serialising everything to JSON twice — once in the service, once in the gateway — doubles CPU for no benefit.

5. Hot keys

A cache or partition keyed by a popular entity concentrates all traffic on one shard. Symptoms: one CPU core saturated while others idle, one partition's lag climbing, one Redis node near its network limit. Fixes are to split the key with a random suffix and merge on read, replicate the hot value to every node, or add a local in-process cache in front of the shared one.

Single Redis node
~100-200k ops/s
A hot key can approach this alone
Single partition
5-50 MB/s
A celebrity key can fill it
Local cache hit
~100 ns
The cheapest shield for a hot key
Key split fan
10-100
More shards, more merge work

6-7. Retry storms and forever storage

Retries during a degradation multiply load exactly when the system can least afford it, and synchronized retries create a wave that never lets the dependency recover. Backoff with jitter, a retry budget, and a breaker are the three-part fix.

Unbounded retention is the quieter one: every event, log line and version kept forever because deletion felt risky. Storage grows linearly with traffic and every query over it gets slower. Set retention from a requirement — 30 days for replay, 7 years for invoices — and tier older data to cheap storage instead of primary disks.

Name the cost, not the technique
"I'd batch those calls into one query, run the independent ones in parallel under a single deadline, and cap fan-out with a hybrid push/pull split so a celebrity post doesn't multiply reads."

Worth remembering

  • Ten sequential 20 ms calls is 200 ms of pure waiting; run independent calls in parallel or batch them.
  • Fan-out to every follower at read time turns a celebrity post into a thundering herd.
  • Over-fetching multiplies bytes at every layer: database, network, serialisation, client memory.
  • Unbounded retention is a storage bill with no product requirement behind it.

Checkpoint

Answer all 3 questions to finish the lesson.
1. Five independent calls each take 60 ms. Why is parallel execution better than sequential beyond the obvious speedup?
Sequential calls add tails: five p99s stack. In parallel the tail is close to the slowest single call.
2. Fan-out on write struggles with celebrity accounts. What is the standard remedy?
Writing two million timeline entries per post is unbounded. Pulling the large accounts at read time and merging keeps both sides bounded.
3. One cache node is saturated while others are idle. What is the likely cause?
Key placement is deterministic, so one popular key lands on one node. Splitting or local caching spreads the load.