SysDesignPrep.com
Study guide 138 of 183

"Fan-out on write vs fan-out on read"

The core trade-off behind feeds, timelines and inboxes: precomputing per-user timelines on write versus assembling them on read, the celebrity problem, hybrid fan-out, ranking, storage cost and how to explain it in an interview.

Reading is half of it. See this used in a real interview: walk through Design a News Feed →

Every feed question (Twitter, Instagram, Facebook, LinkedIn) comes down to one decision: when a user posts, do you copy the post into every follower's timeline now, or do you gather posts from everyone a user follows when they open the app? The first is fan-out on write (push); the second is fan-out on read (pull). Getting this trade-off right, and knowing why big products use a hybrid, is most of a strong feed answer.

Fan-out on write (push)

When Alice posts, a worker looks up her followers and appends the post id to each follower's precomputed timeline, usually a capped list in Redis or a wide-column table keyed by user id.

  • Reads are trivial: open the app, read the first page of your timeline list, hydrate the post ids from a cache. One key, one round trip.
  • Writes are expensive: one post becomes N timeline writes, where N is the follower count.
  • Wasted work: you write into timelines of users who will never open the app this week.
  • Latency of delivery: a post reaches followers over seconds or minutes as the fan-out queue drains.

Fan-out on read (pull)

When Bob opens the app, the feed service fetches recent posts from each account he follows and merges them.

  • Writes are trivial: store the post once, in the author's own list.
  • Reads are expensive: following 500 accounts means 500 lookups (or a scatter-gather across shards) and a merge on every refresh.
  • Always fresh and no wasted work for inactive users.
  • Tail latency suffers, because the slowest of hundreds of lookups sets the response time. See tail latency.

Side by side

Fan-out on writeFan-out on read
Cost paid atpost timeread time
Read latencyvery lowhigher, variable
Write amplificationfollowers per postnone
Storagea timeline per userposts only
Best whenreads far outnumber writes, follower counts moderatefew readers, huge follower counts, or rare reads
Breaks oncelebrities with millions of followersusers who follow thousands of accounts

Feeds are read-heavy (often 100 reads per write), which is why push is the default.

The celebrity problem

A celebrity with 100 million followers would turn one post into 100 million timeline writes, saturating the fan-out workers and delaying everyone else's posts. The standard answer is a hybrid:

  • Normal accounts fan out on write.
  • Accounts above a threshold (say 100 k followers) do not fan out; their posts stay in their own list.
  • At read time, the feed service merges the user's precomputed timeline with recent posts from the few celebrities they follow.

Because a user follows only a handful of celebrities, the read-time merge stays small. The celebrity's recent posts are extremely hot, so cache them aggressively. See hot keys and skew.

Other optimisations

  • Skip inactive users: only fan out to users active in the last N days; rebuild an inactive user's timeline on demand when they return.
  • Store ids, not posts: timelines hold post ids (and maybe author id and timestamp); content is hydrated from a post cache, so edits and deletes apply everywhere.
  • Cap timeline length: keep the latest 500 to 800 ids; older pages fall back to pull.
  • Prioritise the queue: fan-out for users who are online right now first.
  • Deletes and unfollows: filter at read time rather than rewriting millions of timelines; clean up lazily.

Ranking on top

Modern feeds are ranked, not chronological. The fan-out (or pull) step now builds a candidate set; a ranking service scores candidates with features (affinity with the author, engagement, recency) and returns the top items. The precomputed timeline is still useful: it is a cheap, fresh source of candidates. See recommendation systems.

Beyond social feeds

The same trade-off appears elsewhere:

  • Chat: small groups fan out each message to members' inboxes; very large channels are read from the channel log instead. See Design Slack.
  • Notifications: per-user inbox (push) versus computing "what's new" on open.
  • Reddit-style front pages: one shared ranked list per community, computed periodically and read by everyone, which is fan-out on read with heavy caching. See Design Reddit.

How to present it

  1. State the read/write ratio and follower distribution from your estimates.
  2. Pick push as the default because reads dominate.
  3. Raise the celebrity problem yourself and introduce the hybrid threshold.
  4. Mention storing ids, capping timelines, and skipping inactive users.
  5. Add ranking as a layer on top of candidate generation.

Walk through it end to end in Design a News Feed and Design Instagram.

Checklist

  • Read/write ratio and follower distribution estimated first.
  • Push for normal accounts, pull for celebrities, merged at read.
  • Timelines hold capped lists of ids, hydrated from a post cache.
  • Inactive users skipped and rebuilt on demand.
  • Deletes and unfollows filtered at read time.
  • Ranking applied to the merged candidate set.

Open in your browser to sign in

Google does not allow sign-in inside this app's built-in browser. Open this page in Safari and sign in there. The link opens this same page.

Tap the ⋯ or share button at the top or bottom of the screen, then Open in browser. Or copy the link and paste it into Safari.