advanced 2 min answer Multiple choice

A social feed becomes too expensive to generate at read time. Should the system fan out on write, fan out on read, or use a hybrid - and what decides it?

fanoutfeedscelebrity-problemmetacaching
Pick one
Show the full answer Hide the answer

What is being tested

Whether you reason about the distribution of follower counts rather than the average, and whether you recognise the celebrity problem before it is named for you.

The two pure strategies

Fan-out on write (push). When a post is created, write a reference into every follower's feed. Reads become a single sequential lookup — extremely fast, extremely cheap, trivially cacheable. Write cost is proportional to follower count.

Fan-out on read (pull). Store the post once. When a user opens their feed, query the recent posts of everyone they follow and merge. Writes are trivial; reads are expensive, repeated on every refresh, and get worse the more accounts a user follows.

Why the hybrid wins

Follower counts follow an extreme power law. The overwhelming majority of accounts have a few hundred followers, where push costs a few hundred cheap writes. A tiny number have tens of millions, where push means tens of millions of writes for a single post — a write amplification that arrives as a burst and can saturate the storage tier.

So: push for the many, pull for the few. At read time, a user's feed is the union of their materialised push feed and a live query of the small number of very-high-follower accounts they follow. Because that number is small — nobody follows a thousand celebrities — the read-time merge is bounded and cheap.

The threshold is an operational parameter, tuned by measuring, not a constant.

Second-order details that matter

  • Do not push to inactive users. A large fraction of accounts have not opened the app in months. Materialising feeds for them is the largest single waste in a naive push design. Materialise lazily on their return.
  • Store references, not content. The feed holds post IDs; content is fetched from a cache. One edit or deletion then does not require rewriting millions of feed entries.
  • Bound the feed length. Keep the most recent N entries; older content is served by pull.
  • Ranking is a separate concern from delivery. Fan-out decides what is eligible; ranking decides order. Conflating them makes both harder to change.
  • Deletion. A deleted post must disappear from millions of materialised feeds. Filtering at read time against a deletion set is usually cheaper than rewriting feeds.

What "cache the rendered feed" misses

It is not wrong so much as insufficient — it addresses repeated reads by the same user but does nothing about the underlying generation cost on a cache miss, and every new post invalidates it. Caching is a layer on top of whichever fan-out strategy you choose, not a substitute for choosing.

The transferable principle

When a workload's cost is driven by a highly skewed distribution, the right architecture almost always treats the head and the tail as different problems. Designing everything for the 100,000-member case makes the three-member case absurdly expensive; designing everything for the common case falls over on the celebrity. This same shape appears in chat channel fan-out, cache hot keys, and shard distribution.