Write Amplification in Fan-Out Architectures: When One Write Becomes Thousands
Core concept
Some systems must deliver a single write to a very large number of recipients — think a celebrity posting a tweet that 50 million followers need to see. The naive approach is to write to every follower's personal feed the moment the post is created, which means one user action triggers millions of database writes. This is called write amplification: the ratio of actual storage writes to the logical writes a user intended. Keeping that ratio under control is a central tension in any high-fan-out (one-to-many) system.
Diagram
flowchart LR
A[User Post] --> B[Fan-Out Service]
B --> C[Feed Store: User 1]
B --> D[Feed Store: User 2]
B --> E[Feed Store: User N]
F[Cache Layer] --> C
F --> D
F --> E
Concrete real-world example
Twitter historically used a push model (fan-out on write): when you post, a background job copies your tweet ID into each follower's pre-computed feed inbox. Reading your feed is then a single cheap lookup. This works beautifully for ordinary users. But when a user has 50 million followers, that single post creates 50 million small writes — enough to saturate the write path for several seconds. Twitter's engineering team eventually introduced a hybrid model: ordinary users get push fan-out, while celebrity accounts (above a follower threshold, roughly 1 million) are handled with pull fan-out — their posts are fetched and merged into your feed at read time rather than pushed eagerly. The read is slightly more expensive, but the write cost collapses from millions of writes to one.
One trade-off / gotcha
The hybrid model sounds elegant, but it shifts complexity from writes to reads: every feed request must now identify which accounts in your follow list are "celebrities," fetch their latest posts separately, and merge them with your pre-computed push feed — all within the latency budget of a page load (~100–200 ms). Getting the merge wrong means followers see a celebrity post appear and disappear as cache states drift, which looks like a consistency bug even if no data was lost.
An interview-style question to ponder
You're designing a social media feed system. A user follows 800 accounts: 790 normal users and 10 celebrities each with >5 million followers. Describe how you'd store and retrieve this user's feed, and justify your fan-out strategy for each account type.
Stuck? Show a hint
Think about where the cost lands — at write time or read time — for each account type, and ask what happens at the extremes: what breaks if you push to everyone, and what breaks if you pull from everyone?
Show answer
Use push fan-out for normal accounts and pull fan-out for celebrities, merging both at read time.
- For the 790 normal accounts: when any of them posts, write that post ID into this user's feed inbox (a sorted list, keyed by timestamp). The write cost is small — 790 accounts each have a modest follower count, so the total fan-out across the whole system is manageable. Reading the feed is a single lookup of the pre-computed inbox.
- For the 10 celebrity accounts: do not write into every follower's inbox on post. Instead, maintain a per-celebrity recent-posts list (just the last N post IDs, say 200). At read time, fetch the user's push inbox plus each celebrity's recent-posts list, then merge-sort them by timestamp. Ten fetches of small lists adds roughly one extra round-trip, which fits inside a 150 ms budget if the celebrity lists are in a fast cache (an in-memory store like Redis — a key-value store optimized for speed).
- The threshold matters: set it too low (e.g., >10k followers = celebrity) and you move too many accounts to pull, making reads expensive. Set it too high and you let moderately popular accounts still generate painful write spikes. Most real systems tune this threshold empirically and re-evaluate it as traffic patterns shift.
- But why not just pull everything and skip fan-out entirely? Pure pull is tempting for simplicity, but a user following 800 accounts would require fetching and merging 800 separate post lists on every feed load — that's 800 sequential or parallel lookups, dominating read latency and hammering storage with hot-key traffic on popular accounts.
- Watch out: even the merge step can become a bottleneck if celebrity lists aren't cached aggressively — a single viral celebrity can turn every user's feed read into a cache miss thunderstorm.