32 - Design News Feed

Series: System Design & Distributed Systems Previous: 31 - Design Chat System | Next: 33 - Design YouTube or Netflix


1. Requirements

Functional Requirements

FeatureDetails
Create postText, images, video, links
View news feedAggregated posts from friends/followed users
Like, comment, shareEngagement actions
PaginationEfficient scrolling through feed
NotificationsAlert on friend activity (optional)

Non-Functional Requirements

  • Latency: Feed loads in < 500ms
  • Availability: 99.99%
  • Freshness: New posts appear within seconds for close friends
  • Scale: 1B users, 300M DAU, avg 500 friends per user
  • Ranking: Not purely chronological -- relevance matters

2. Capacity Estimation

DAU:                    300M
Avg posts created/day:  2 per active user = 600M posts/day
Avg feed fetches/day:   10 per user = 3B feed reads/day
Avg friends:            500
Fan-out write volume:   600M posts x 500 friends = 300B writes/day (push model)
Feed read QPS:          3B / 86400 = ~35K QPS
Peak read QPS:          ~70K QPS
ResourceEstimate
Post storage/day~600M posts x 1KB = 600GB
Feed cache per user~2000 post IDs x 8B = 16KB
Total feed cache300M users x 16KB = ~5TB

3. High-Level Architecture

+---------+         +--------------+        +-----------+
| Client  |-------->| API Gateway  |------->| Post      |
| (App)   |         |              |        | Service   |
+---------+         +-+------+-----+        +-----+-----+
                      |      |                    |
                      |      |              +-----+------+
                      |      |              | Post DB    |
                      |      |              | (MySQL/    |
                      |      |              |  Postgres) |
                      |      |              +------------+
                      |      |
               +------+      +--------+
               |                      |
        +------+------+       +-------+------+
        | Feed        |       | Feed         |
        | Generation  |       | Retrieval    |
        | Service     |       | Service      |
        +------+------+       +-------+------+
               |                      |
        +------+------+       +-------+------+
        | Fan-out     |       | Feed Cache   |
        | Workers     |       | (Redis)      |
        +------+------+       +--------------+
               |
        +------+------+
        | Message     |
        | Queue       |
        | (Kafka)     |
        +-------------+

4. Feed Generation: Three Approaches

Approach 1: Fan-Out on Write (Push Model)

User A creates post
       |
       v
Fan-out Service reads A's follower list
       |
       v
For each follower, prepend post_id to their feed cache
       |
  +----+----+----+----+
  |    |    |    |    |
  F1   F2   F3   F4  ...FN
  feed feed feed feed  feed
ProsCons
Feed read is O(1) -- just fetch from cacheWrite amplification: celebrity with 10M followers = 10M writes
Low latency on readWasted work for inactive users who never check feed
Simple feed retrievalHot users create thundering herd on write path

Approach 2: Fan-Out on Read (Pull Model)

User B opens feed
       |
       v
Feed Service fetches B's friend list
       |
       v
For each friend, query their recent posts
       |
       v
Merge, rank, return top N
ProsCons
No write amplificationSlow: must query N friends' timelines on every read
No wasted computationHigh read latency, especially for users with 1000+ friends
Fresh results every timeHard to rank without pre-computation

Approach 3: Hybrid (Facebook's Approach)

                    Is poster a celebrity?
                           |
                   +-------+-------+
                   |               |
                  YES              NO
                   |               |
            Pull on read     Push to followers'
            (lazy fetch)     feed cache (fan-out)
User TypeStrategyReason
Normal user (< 10K followers)Fan-out on writeLow fan-out cost, fast reads
Celebrity (> 10K followers)Fan-out on readAvoid millions of writes per post
Close friendsFan-out on write + priorityEnsure low-latency delivery

Interview Tip: Always propose the hybrid approach. Explain the celebrity problem first, then show how the hybrid solves it. This demonstrates depth.


5. Feed Ranking Algorithm

Simple Chronological

score = timestamp

Engagement-Based (EdgeRank, simplified)

score = affinity x weight x time_decay

affinity    = how close is the poster to the viewer (interaction history)
weight      = type of content (video > photo > text > link)
time_decay  = 1 / (now - post_time)^gravity

Modern ML Ranking

Feed candidates (1000s)
       |
       v
  Stage 1: Candidate retrieval (lightweight model)
       |
       v
  Stage 2: Feature extraction
       |   - User features (age, location, interests)
       |   - Post features (type, engagement, recency)
       |   - Cross features (past interactions between user and poster)
       |
       v
  Stage 3: Ranking model (deep learning)
       |   - Predict: P(like), P(comment), P(share), P(hide)
       |   - Combine into final score
       |
       v
  Stage 4: Re-ranking (diversity, dedup, policy filters)
       |
       v
  Top 50 posts returned

6. News Feed Cache

Cache Structure (Redis Sorted Set per User)

feed:{user_id} = sorted set of (post_id, score)

Example:
feed:U123 = {
  (post_789, 0.95),
  (post_456, 0.88),
  (post_123, 0.72),
  ...
}

Cache Operations

OperationCommandComplexity
Add post to feedZADDO(log N)
Get top N postsZREVRANGEO(log N + M)
Trim old postsZREMRANGEBYRANKO(log N + M)
Remove post (deleted)ZREMO(log N)

Cache Policy

  • Keep latest 2000 post IDs per user
  • TTL: 7 days for inactive users
  • Cache-aside pattern: miss triggers on-the-fly generation

7. Pagination: Cursor-Based

Why Not Offset-Based?

Problem: New posts push items down, causing duplicates or skips

Page 1: [A, B, C, D, E]
          ^--- New post X inserted here
Page 2: [E, F, G, H, I]  <-- E appears twice!

Cursor-Based Pagination

GET /feed?cursor=post_456&limit=20

Response:
{
  "posts": [...20 posts...],
  "next_cursor": "post_789",
  "has_more": true
}
  • Cursor = last seen post ID or timestamp
  • Stable regardless of new inserts
  • Works naturally with sorted sets in Redis

Interview Tip: Always propose cursor-based pagination for feeds. Mention that offset-based has the "shifting window" problem.


8. Social Graph Storage

Graph Database or Adjacency List

+------------+     follows      +------------+
|   User A   |----------------->|   User B   |
+------------+                  +------------+
      |                               |
      | follows                       | follows
      v                               v
+------------+                  +------------+
|   User C   |                  |   User D   |
+------------+                  +------------+

Storage Options

OptionUse CaseTrade-off
Adjacency list (MySQL)< 100M edgesSimple, ACID
Graph DB (Neo4j, TAO)Social graph queriesFast traversal, complex ops
Redis set per userFan-out lookupUltra-fast reads

Facebook TAO

  • Distributed graph store built on MySQL shards
  • Two tables: Objects (users, posts) and Associations (follows, likes)
  • Heavy caching layer on top
  • Handles billions of edges

9. Media Storage

Client --> Upload Service --> Object Store (S3)
                |                  |
                v                  v
         Metadata DB         CDN (CloudFront)
         (post_id,           (serve to clients)
          media_url,
          dimensions)

Optimization

  • Generate multiple sizes: thumbnail (150px), medium (600px), full (1200px)
  • Serve responsive images based on device screen
  • Lazy load below-the-fold media
  • AVIF/WebP with JPEG fallback

10. Post Creation Flow

Client                API GW           Post Service         Fan-out
  |                     |                   |                  |
  |-- Create post ----->|                   |                  |
  |                     |-- Validate ------>|                  |
  |                     |                   |-- Store in DB -->|
  |                     |                   |                  |
  |                     |                   |-- Enqueue ------>|
  |                     |<-- 201 Created ---|                  |
  |<-- Post created ----|                   |                  |
  |                     |                   |           +------+------+
  |                     |                   |           | Fan-out to  |
  |                     |                   |           | followers'  |
  |                     |                   |           | feed caches |
  |                     |                   |           +-------------+

Steps

  1. Client sends post content + media URLs
  2. API Gateway authenticates and rate-limits
  3. Post Service validates, stores in Post DB
  4. Post Service enqueues fan-out event to Kafka
  5. Fan-out workers read follower list, push to feed caches
  6. Response returned to client without waiting for fan-out

11. Feed Freshness

Problem

Cached feeds can become stale. New posts from friends may not appear.

Solutions

TechniqueHow It Works
Push on writeFan-out ensures feed cache is updated immediately
Pull on openWhen user opens app, fetch recent posts from close friends
Hybrid refreshBackground job periodically refreshes cold caches
Real-time updatesWebSocket/SSE pushes new post IDs to active clients

Real-Time Feed Update

Fan-out Worker --> Notification Service --> WebSocket to Client
                                               |
                                          "New post from Alice"
                                          Client prepends to feed

12. Notification on New Posts

Post Created --> Kafka --> Notification Service
                              |
                    +---------+---------+
                    |         |         |
                 In-App    Push       Email
                 Badge    (APNs/FCM)  (digest)
  • Don't notify for every post (notification fatigue)
  • Prioritize: close friends > acquaintances > pages
  • Batch digest emails: "Here's what you missed today"

13. Complete System Diagram

+--------+  +--------+  +--------+
|Client 1|  |Client 2|  |Client N|
+---+----+  +---+----+  +---+----+
    |           |            |
    +-----+-----+-----+-----+
          |           |
   +------+------+    |
   |    CDN      |    |
   | (media)     |    |
   +-------------+    |
                      |
              +-------+--------+
              |  API Gateway   |
              | (Auth, Rate    |
              |  Limit, Route) |
              +---+---+---+---+
                  |   |   |
       +----------+   |   +----------+
       |              |              |
+------+------+ +-----+------+ +----+-------+
| Post        | | Feed       | | User       |
| Service     | | Service    | | Service    |
+------+------+ +-----+------+ +----+-------+
       |               |              |
  +----+----+    +-----+------+  +---+--------+
  | Post DB |    | Feed Cache |  | Social     |
  | (MySQL  |    | (Redis     |  | Graph DB   |
  | sharded)|    |  Cluster)  |  | (MySQL/TAO)|
  +---------+    +------------+  +------------+
       |
  +----+--------+
  | Kafka       |
  +----+--------+
       |
  +----+--------+
  | Fan-out     |
  | Workers     |
  +----+--------+
       |
  +----+--------+--------+
  |             |         |
+--+---+  +----+---+ +---+------+
|Feed  |  |Notif   | |Analytics |
|Cache |  |Service | |Service   |
|Update|  +--------+ +----------+
+------+

14. Trade-Off Summary

DecisionOption AOption BRecommendation
Fan-outOn write (push)On read (pull)Hybrid
PaginationOffsetCursorCursor
RankingChronologicalML-basedML with chrono fallback
Graph storeRelationalGraph DBDepends on scale
CacheWrite-throughCache-asideCache-aside for feed

15. Interview Tips

  1. Lead with the hybrid fan-out: This is THE key insight for this problem
  2. Celebrity problem: Always mention it -- shows you understand scale
  3. Ranking: At minimum, mention affinity + recency + content type
  4. Cache is king: Feed cache in Redis is what makes reads fast
  5. Cursor pagination: Mention the "shifting window" problem with offset
  6. Don't overcomplicate: If interviewer says "chronological only", skip ML ranking
  7. Numbers matter: Know that fan-out for 500 friends x 600M posts = 300B writes

16. Resources

  • Alex Xu - System Design Interview Vol. 1, Chapter 11: Design a News Feed System
  • Facebook Engineering: "Serving Facebook Multifeed" (2015)
  • Facebook TAO Paper: "TAO: Facebook's Distributed Data Store for the Social Graph"
  • Instagram Engineering: "Scaling the Instagram Explore Feed"
  • Twitter Engineering Blog: "The Infrastructure Behind Twitter: Scale"
  • Martin Kleppmann - Designing Data-Intensive Applications, Chapter 3 (Indexes)

Previous: 31 - Design Chat System | Next: 33 - Design YouTube or Netflix