Vasu Patel logoVasu Patel
← Designing at Scale: System Design
All chapters in this track
  1. 01Chapter 1: Why System Design Is Its Own Skill
  2. 02Chapter 2: Core Building Blocks and Vocabulary
  3. 03Chapter 3: Eliciting Non-Functional Requirements
  4. 04Chapter 4: Back-of-Envelope Capacity Estimation
  5. 05Chapter 5: Caching Strategies and Cache Invalidation at the Systems Level
  6. 06Chapter 6: Load Balancing and Horizontal Scaling
  7. 07Chapter 7: Database Selection, Replication, and Sharding at a Systems Level
  8. 08Chapter 8: Asynchronous Processing, Message Queues, and Event-Driven Design
  9. 09Chapter 9: API Design from a Systems Perspective: REST, gRPC, GraphQL
  10. 10Chapter 10: The CAP Theorem and Consistency Models in Practical Terms
  11. 11Chapter 11: Microservices vs. Monoliths and Drawing Service Boundaries
  12. 12Chapter 12: Designing for Failure: Redundancy, Failover, Graceful Degradation
  13. 13Chapter 13: A Repeatable Framework for Any System Design Problem
  14. 14Chapter 14: Worked Example: URL Shortener
  15. 15Chapter 15: Worked Example: Chat System
  16. 16Chapter 16: Worked Example: News Feed
  17. 17Chapter 17: Worked Example: Rate Limiter

Chapter 16 of 17

Chapter 16: Worked Example: News Feed

Why this matters

The news feed worked example exercises the classic fan-out trade-off — a problem genuinely unique to this kind of system among the four worked examples, and one where the "obvious" solution breaks down in a specific, instructive way at scale (the "celebrity problem," covered below).

Step 1: Clarify requirements

Clarifying questions: "Should the feed be strictly reverse-chronological, or algorithmically ranked? How many people does a typical user follow? Are there 'celebrity' accounts with a very large number of followers? How fresh does the feed need to be (near real-time, or is some delay acceptable)?"

Assumed answers: reverse-chronological for simplicity in this example; average user follows ~200 accounts, but some celebrity accounts have 10+ million followers; near real-time freshness is desired but a few seconds of delay is acceptable.

Step 2: Estimate scale

Assume 50 million daily active users, each posting ~2 posts/day and
checking their feed ~10 times/day.

Posts created: 50M x 2 = 100M posts/day ≈ 1,157 posts/second (average)
Feed reads: 50M x 10 = 500M feed views/day ≈ 5,787 reads/second (average)
   -- READS dominate WRITES by roughly 5:1 here, though both are
   substantial in absolute terms (unlike the URL shortener's more
   extreme read skew).

Step 4 (deep-dive comes before step 3's full detail here, since the fan-out decision drives the entire high-level design)

Why this is the hardest part, identified upfront: "The core design decision for a news feed is when the feed for each user actually gets assembled — at post-time (fan-out-on-write) or at read-time (fan-out-on-read) — and this single decision shapes nearly everything else about the architecture, so I'd like to work through it before sketching the rest."

Option A — Fan-out-on-write (push): when a user posts, immediately push that post into the pre-computed feed of every one of their followers.

User posts -> for EACH of the user's followers, insert this post into
              that follower's pre-computed feed (stored in a fast
              key-value store, Chapter 5) -> when a follower checks
              their feed, it's ALREADY assembled -- extremely fast read.

Cost: a user with 10 million followers triggers 10 million individual
writes for ONE post -- this is the "celebrity problem," and it can
overwhelm the write path badly for popular accounts.

Option B — Fan-out-on-read (pull): don't pre-compute anything at post-time; when a user checks their feed, query all the accounts they follow for recent posts and merge the results on the fly.

User checks feed -> query recent posts from EACH of the ~200 accounts
                     they follow -> merge and sort by time -> return.

Cost: reading becomes more expensive (querying and merging from 200
sources on every single feed check), but writing is trivially cheap
(a post is written ONCE, regardless of follower count).

The chosen approach — a deliberate hybrid, directly addressing the celebrity problem: "Given that reads substantially outnumber writes in the general case, fan-out-on-write is usually the better default — but the celebrity problem makes a pure fan-out-on-write approach genuinely break for high-follower accounts. I'd use a hybrid: fan-out-on-write for accounts under some follower threshold (say, 100,000), and fan-out-on-read specifically for celebrity accounts above that threshold — a typical user's feed is assembled by combining their pre-computed feed (from normal accounts they follow) with a live, on-the-fly query for any celebrity accounts they follow. This directly targets the actual problem (a small number of accounts with an extreme, atypical fan-out cost) rather than either extreme applied uniformly."

Step 3: Sketch the high-level design (informed by the fan-out decision)

Client --> Load Balancer --> Feed Service
                                   |
                    +--------------+--------------+
                    v                              v
        Pre-computed Feed Store              Post Database
        (Redis -- per-user feed,             (source of truth for all
         populated via fan-out-on-write        posts, sharded by post ID
         for normal accounts)                   or user ID)
                    |
                    v
        (at read time, merged with a live query to celebrity
         accounts' recent posts, per the hybrid fan-out decision)

Step 5: Discuss trade-offs and failure modes

"The 100,000-follower threshold is a tunable parameter — I'd want real usage data to calibrate it correctly rather than treating it as fixed. If the pre-computed feed store were to fail, feeds would need to fall back entirely to fan-out-on-read for every user (graceful degradation, Chapter 12) — slower, but the system would remain functional rather than fully failing. I explicitly did not choose strong consistency for feed freshness — a few seconds of delay before a new post appears in followers' feeds is an acceptable trade-off (Chapter 10's per-component consistency reasoning) given the stated requirement tolerates near-real-time rather than strictly instantaneous freshness."

Common mistakes

  1. Proposing pure fan-out-on-write without considering the celebrity problem, missing the single most distinguishing, interesting trade-off this specific system presents.
  2. Proposing pure fan-out-on-read without recognizing that reads substantially outnumber writes in the general case, missing an opportunity to optimize for the dominant access pattern for the majority of (non-celebrity) accounts.
  3. Not identifying the fan-out decision as the component to deep-dive, instead spending equal time on components (load balancing, basic caching) that are comparatively standard and less distinguishing for this specific system.
  4. Treating the follower-count threshold as an arbitrary, uncalibrated constant rather than acknowledging it as a tunable parameter that would need real usage data to set correctly.

Chapter summary / cheat sheet

  • The news feed's defining design decision: fan-out-on-write (fast reads, expensive writes for high-follower accounts) versus fan-out-on-read (cheap writes, more expensive reads) — a genuinely different trade-off shape from either previous worked example.
  • The "celebrity problem" (an account with millions of followers making pure fan-out-on-write prohibitively expensive per post) is the specific reason a hybrid approach (fan-out-on-write below a follower threshold, fan-out-on-read above it) is the strongest answer.
  • This worked example demonstrates identifying the hardest component (the fan-out decision) even before fully sketching the high-level design, since that decision shapes the entire subsequent architecture.
  • Feed freshness tolerates eventual consistency (a few seconds' delay is acceptable) — directly applying Chapter 10's per-component consistency reasoning rather than defaulting to strong consistency everywhere.