Requirements & Scope
Functional Requirements
Core features of a Facebook/LinkedIn-style news feed:
- Create Posts: Users publish text, images, videos, links, or status updates
- View Feed: Users see a feed of posts from connections/friends, sorted chronologically or by relevance
- Like/Comment: Users engage with posts through reactions and threaded comments
- Share/Repost: Users share posts to their own network
- Follow Connections: Users connect with others to see their posts in feed
- Notifications: Users receive alerts for interactions on their posts
Non-Functional Requirements
| Requirement | Target | Rationale |
|---|---|---|
| Feed Generation Latency | < 500ms | Users expect instant feed load |
| Availability | 99.99% | Social platforms must always be accessible |
| Consistency | Eventual consistency OK | A few seconds delay for new posts is acceptable |
| Throughput | 100K posts/sec write, 500K feed reads/sec | LinkedIn-scale numbers |
| Durability | All posts must be persisted permanently | Users expect data persistence |
| Media Support | Images, videos, links with previews | Rich content is essential |
| Scalability | 1B+ registered users, 500M+ DAU | Must handle massive scale |
Core Entities
User: { user_id, name, email, profile_pic, created_at }
Post: { post_id, user_id, content, media_urls, post_type, visibility, created_at }
Like: { like_id, user_id, post_id, reaction_type, created_at }
Comment: { comment_id, user_id, post_id, parent_id, content, created_at }
Follow: { follower_id, followee_id, created_at }
Feed: { user_id, post_ids[], last_updated }
Share: { share_id, user_id, original_post_id, commentary, created_at }
Capacity Estimation
Write load: 100M posts/day = ~1,160 posts/sec avg, ~3,000 posts/sec peak
Read load: Each user views feed ~15 times/day = 7.5B reads/day = ~87K reads/sec avg
Storage: 100M posts/day * 2KB avg (including metadata) = 200GB/day = ~73TB/year
Media: 100M posts * 30% have media * 500KB avg = 15TB/day
Comments: ~500M comments/day = ~5.8K comments/sec
Key Design Decisions
- Feed ordering: Chronological (simple) vs algorithmic/ranked (engagement-optimized)
- Fanout strategy: Push vs pull vs hybrid for feed generation
- Media handling: CDN for images/videos, async upload processing
- Comment threading: Flat vs nested comment structure
- Real-time updates: Long-polling, WebSockets, or periodic polling
Fanout on Write
How Fanout on Write Works
When a user creates a post, the system immediately pushes the post ID to all followers' pre-computed feed caches.
User creates post
|
v
Post Service stores post in DB
|
v
Publishes "new_post" event to Kafka
|
v
Fanout Workers consume event
|
+---> Push post_id to Follower 1's feed cache
+---> Push post_id to Follower 2's feed cache
+---> Push post_id to Follower 3's feed cache
+---> ... (all followers)
Implementation
Fanout Worker Logic
def fanout_post(post, author):
follower_ids = get_follower_ids(author.id)
pipeline = redis.pipeline()
for follower_id in follower_ids:
# Add post to follower's feed sorted set (scored by timestamp)
pipeline.zadd(
f"feed:{follower_id}",
{post.id: post.created_at.timestamp()}
)
# Trim to keep only last 1000 posts per user
pipeline.zremrangebyrank(f"feed:{follower_id}", 0, -1001)
# Send notification (async, separate pipeline)
if is_active(follower_id):
notify(follower_id, post)
pipeline.execute() # Single atomic batch
Feed Read Path
def get_feed(user_id, page=1, count=50):
offset = (page - 1) * count
# 1. Get post IDs from Redis sorted set
post_ids = redis.zrevrange(f"feed:{user_id}", offset, offset + count - 1)
# 2. Batch fetch full post details from database
posts = batch_get_posts(post_ids)
# 3. Hydrate with author info, like counts, comment counts
hydrated = hydrate_posts(posts)
return hydrated
Pros and Cons
| Pros | Cons |
|---|---|
| Feed reads are extremely fast (O(1) lookup) | Write amplification: 1 post = N writes (N = follower count) |
| No computation at read time | Wasted work for users who never check their feed |
| Simple read path, easy to cache | Popular users cause massive fanout bursts |
| Predictable read latency | Storage overhead: each user's feed is duplicated |
When to Use Fanout on Write
- Users typically have a bounded number of connections (< 5,000)
- Read-to-write ratio is high (users read much more than they post)
- Low latency feed generation is critical
- System can tolerate some write amplification
Fanout on Read
How Fanout on Read Works
When a user opens their feed, the system dynamically fetches recent posts from all their connections and merges them in real-time.
User opens feed
|
v
Feed Service receives request
|
v
Get list of followees (who user follows)
|
v
Query recent posts from each followee (parallel)
|
+---> User A: latest 20 posts
+---> User B: latest 20 posts
+---> User C: latest 20 posts
+---> ... (all followees)
|
v
Merge all posts, sort by timestamp
|
v
Apply ranking model (optional)
|
v
Return top N posts to client
Implementation
Feed Read Logic
def get_feed(user_id, count=50):
# 1. Get followee list
followee_ids = get_followees(user_id) # From graph DB or cache
# 2. Fetch recent posts from each followee (parallel queries)
all_posts = []
with ThreadPool(max_workers=20) as pool:
futures = [
pool.submit(get_recent_posts, fid, limit=20)
for fid in followee_ids
]
for future in futures:
all_posts.extend(future.result())
# 3. Merge and sort by timestamp
all_posts.sort(key=lambda p: p.created_at, reverse=True)
# 4. Apply ranking (optional)
ranked_posts = rank_posts(all_posts, user_id)
return ranked_posts[:count]
Database Queries
-- Get recent posts from a specific user
SELECT post_id, content, media_urls, created_at
FROM posts
WHERE user_id = ? AND visibility = 'public'
ORDER BY created_at DESC
LIMIT 20;
-- Get followees of a user
SELECT followee_id
FROM follows
WHERE follower_id = ?;
Pros and Cons
| Pros | Cons |
|---|---|
| No write amplification | Slow reads: must query all followees |
| Always shows freshest content | Latency scales with number of followees |
| No wasted computation | Computationally expensive at read time |
| Storage efficient (no duplicate feeds) | Hard to meet <500ms SLA for users with many connections |
Caching Optimizations
- Cache followee lists in Redis to avoid graph DB lookups on every read
- Cache recent posts per user in Redis to reduce DB queries
- Use read replicas for post queries to distribute read load
- Pre-warm feeds for high-traffic users during off-peak hours
Hybrid Approach
The Hybrid Strategy
Combine fanout-on-write for normal users with fanout-on-read for high-follower accounts.
User creates post
|
v
Post Service stores post
|
v
Check author's follower count:
|
+-- < 10,000 followers --> Fanout Service pushes to followers' feeds
|
+-- >= 10,000 followers --> No fanout; pull at read time
Feed Read with Hybrid
def get_feed_hybrid(user_id, count=50):
# 1. Get pre-computed feed from Redis (push-based posts)
pre_computed_ids = redis.zrevrange(f"feed:{user_id}", 0, count * 2)
pre_computed_posts = batch_get_posts(pre_computed_ids)
# 2. Get followed high-follower accounts
high_follower_ids = get_followed_high_follower_accounts(user_id)
# 3. Pull recent posts from high-follower accounts
pull_posts = []
for hf_id in high_follower_ids:
posts = get_recent_posts(hf_id, limit=5)
pull_posts.extend(posts)
# 4. Merge, deduplicate, and sort
all_posts = merge_and_dedup(pre_computed_posts, pull_posts)
all_posts.sort(key=lambda p: p.created_at, reverse=True)
# 5. Apply ranking
ranked = apply_ranking_model(all_posts, user_id)
return ranked[:count]
Threshold Design
| Follower Count | Strategy | Fanout Cost | Read Cost |
|---|---|---|---|
| < 1,000 | Push only | Minimal | Very fast |
| 1,000 - 10,000 | Push only | Moderate | Fast |
| 10,000 - 100,000 | Hybrid (pull this user's posts) | N/A for this user | Slight delay |
| > 100,000 | Pull only | Zero | Must pull |
Migration Logic
When a user crosses the threshold (e.g., from 9,999 to 10,000 followers):
- Stop pushing new posts to followers' feeds
- Existing pushed posts remain in followers' caches until they expire
- Mark user as "high-follower" in metadata
- Followers' read path automatically starts pulling from this user
Benefits of Hybrid
- 95% of users have <1,000 followers — fanout-on-write works perfectly
- Top 5% of users (influencers, brands) use pull — avoids massive fanout
- Feed latency remains <500ms for all users
- Write amplification stays bounded
- This is what Facebook, LinkedIn, and Instagram actually use
Ranking & Optimization
Feed Ranking Models
Chronological (Simple)
Sort posts by creation timestamp, newest first. Simple but may show low-quality or irrelevant content.
Engagement-Based Ranking
Predict the probability a user will engage (like, comment, share, click) with each post.
score(post, user) = w1 * recency(post)
+ w2 * affinity(user, post.author)
+ w3 * content_quality(post)
+ w4 * engagement_rate(post)
+ w5 * post_type_weight(post.type)
Ranking Signal Breakdown
| Signal | Description | Weight |
|---|---|---|
| Recency | How recent is the post (exponential decay) | 0.3 |
| Affinity | How often user interacts with author | 0.25 |
| Engagement Rate | Likes/comments/shares per impression | 0.2 |
| Content Quality | Text quality, image resolution, spam score | 0.15 |
| Post Type | Video > Photo > Link > Text (engagement varies) | 0.1 |
ML Ranking Pipeline
1. Candidate Generation: Fetch ~500 candidate posts (pull + push feeds)
2. Feature Extraction: Extract user, post, and interaction features
3. Model Scoring: Run through ranking model (e.g., XGBoost, neural net)
4. Filtering: Remove blocked/muted users, already-seen posts
5. Diversification: Ensure mix of content types, authors
6. Return top 50 posts to client
Optimization Strategies
CDN for Media
Client --> CDN Edge (cached media)
|
+--> Cache HIT: serve from edge (< 50ms)
+--> Cache MISS: fetch from S3 origin, cache at edge
- Images served from nearest CDN edge location
- Videos use adaptive bitrate streaming (HLS/DASH)
- Thumbnails pre-generated and cached
Background Pre-fetching
On app open (background thread):
1. Fetch next page of feed while user reads current page
2. Pre-load images for visible posts
3. Pre-fetch comments for posts near viewport
Async Processing
- Like/comment counts updated asynchronously via Kafka events
- Notification delivery is async (separate service)
- Media processing (thumbnails, transcoding) is async
- Feed ranking model runs in background, updates cached feed scores
Pagination & Infinite Scroll
GET /api/feed?cursor=<timestamp>&limit=50
Response:
{
"posts": [...],
"next_cursor": "2024-01-15T10:30:00Z",
"has_more": true
}
Use cursor-based pagination (not offset) for consistent results during concurrent writes.
Handling Viral Content
When a post gets millions of views/engagements in minutes:
- Rate limit comments to prevent database overload
- Cache hot post at CDN edge and application cache
- Queue comment writes through Kafka to smooth out spikes
- Shard post data across multiple partitions if needed
- Degrade gracefully: show cached like counts, delay real-time updates
Practice Problems
Implement a post visibility system that supports public, friends-only, custom lists, and audience restrictions for posts in the news feed.
Design a threaded comment system that supports nested replies, real-time updates, and efficient storage for posts with thousands of comments.
Quiz
1. In fanout-on-write, what happens when a user with 100,000 followers creates a post?
2. What is the main disadvantage of fanout-on-read compared to fanout-on-write?
3. Why do Facebook, LinkedIn, and Instagram use a hybrid approach for feed generation?
4. What database is typically used for storing the primary post data in a news feed system?
5. What is cursor-based pagination and why is it preferred over offset-based pagination for feeds?
6. In a ranking model for news feed, what does the 'affinity' signal measure?
7. What is the purpose of the candidate generation step in an ML ranking pipeline?
8. How does a CDN help optimize news feed performance?
Flashcards
Question
What is the difference between fanout-on-write and fanout-on-read in a news feed system?
Click to reveal answer
Answer
Fanout-on-write pushes post IDs to all followers' feed caches when a post is created (fast reads, expensive writes). Fanout-on-read fetches posts from all followees dynamically when the feed is requested (no write amplification, slow reads).
Question
Why is a hybrid fanout approach preferred in production news feed systems?
Click to reveal answer
Answer
It combines push for normal users (fast reads, manageable write cost) with pull for high-follower accounts (avoids massive write amplification). This balances latency and write efficiency — 95% of users have <1K followers, so push works well for them.
Question
What signals does a news feed ranking model typically use?
Click to reveal answer
Answer
Recency (exponential time decay), affinity (interaction frequency with author), engagement rate (likes/comments/shares per view), content quality (spam score, text analysis), and post type weight (video > photo > link > text).
Question
Why is cursor-based pagination preferred over offset-based pagination for infinite scroll feeds?
Click to reveal answer
Answer
Cursor-based pagination uses the last item's timestamp/ID as a bookmark. When new posts are added, it avoids skipping or duplicating posts. Offset-based pagination breaks under concurrent writes, causing inconsistent feed results.
Question
What are the three main steps of an ML-based feed ranking pipeline?
Click to reveal answer
Answer
1) Candidate Generation: fetch ~500 candidate posts with simple heuristics. 2) Scoring: run ML model (XGBoost/neural net) on candidates. 3) Filtering and Diversification: remove blocked/muted content, ensure variety, return top N posts.
Question
How does a CDN optimize media delivery in a news feed?
Click to reveal answer
Answer
CDN caches images, videos, and thumbnails at edge locations worldwide. When a user loads their feed, media is served from the nearest edge (< 50ms latency) instead of the origin server. This reduces load times and bandwidth costs significantly.
Question
What is write amplification and why is it a concern in fanout-on-write?
Click to reveal answer
Answer
Write amplification occurs when one logical write (creating a post) triggers multiple physical writes (pushing to N followers' caches). For a user with 50K followers, one post = 50K Redis writes. This can overwhelm the write path and cause cascading failures.
Question
What storage system is best for pre-computed feed caches and why?
Click to reveal answer
Answer
Redis sorted sets are ideal. They provide O(log N) retrieval of the most recent items, support time-based scoring, allow atomic batch writes, and operate from memory with sub-millisecond latency. ZREVRANGE fetches the latest N posts instantly.
Question
How should you handle viral content that suddenly gets millions of views?
Click to reveal answer
Answer
1) Cache the hot post at CDN and application layers. 2) Rate-limit comments to prevent DB overload. 3) Queue writes through Kafka to smooth spikes. 4) Shard post data across partitions if needed. 5) Degrade gracefully — show cached counts, delay real-time updates.
Question
What role does Kafka play in a news feed architecture?
Click to reveal answer
Answer
Kafka serves as the event backbone: new posts, likes, comments, and follows are published as events. Fanout workers consume post events to update feed caches. Async processing decouples write-heavy operations from the main request path, improving reliability and throughput.
Revision Notes
Key Takeaways
- 1.News feed systems must balance fast feed generation (<500ms) with efficient write operations at massive scale
- 2.Fanout-on-write gives fast reads but suffers from write amplification; fanout-on-read avoids writes but is slow
- 3.The hybrid approach (push for normal users, pull for high-follower accounts) is the production standard used by Facebook, LinkedIn, and Instagram
- 4.Feed ranking transforms chronological feeds into engagement-optimized feeds using recency, affinity, engagement rate, and content quality signals
- 5.ML ranking pipelines use candidate generation followed by model scoring to efficiently rank hundreds of posts
- 6.Cursor-based pagination ensures consistent feed results when new posts are added concurrently
- 7.CDN is essential for media delivery — images and videos served from edge locations with <50ms latency
- 8.Kafka enables async processing of fanout, likes, comments, and notifications, decoupling write-heavy operations from the request path
Interview Tips
- •Always start by clarifying scope — ask about scale (100M vs 1B users), features (do we need stories/reels?), and latency requirements
- •Draw the write path and read path separately on the whiteboard — interviewers want to see both flows clearly
- •Proactively mention the celebrity/high-follower problem — it shows you understand real-world scaling challenges
- •Explain WHY you chose each technology — not just 'use Redis' but 'use Redis sorted sets because ZREVRANGE gives O(log N) time-ordered retrieval'
- •When discussing ranking, start simple (chronological) then layer on complexity (ML ranking) — don't jump to the hardest solution first
- •Discuss trade-offs explicitly for every decision — push vs pull, consistency vs availability, real-time vs batch processing
- •Mention failure modes and monitoring — what happens when Redis goes down? How do you detect fanout lag?
- •End with optimization discussion — CDN for media, background pre-fetching, rate limiting for viral content — shows production-minded thinking
Cheat Sheet
News Feed System Design - Cheat Sheet
Functional Requirements
- Create posts (text, images, videos, links), view feed, like/comment, share, follow connections, notifications
Non-Functional Requirements
- Feed generation < 500ms, 99.99% availability, eventual consistency OK, 100K posts/sec write, 500K feed reads/sec
Architecture Components
| Component | Purpose |
|---|---|
| Post Service | Validate, store posts, trigger fanout events |
| Fanout Service | Push post IDs to followers' feed caches |
| Feed Service | Read from cache, pull celebrity posts, apply ranking |
| Ranking Service | Score posts using ML model, return ranked feed |
| Notification Service | Send alerts for likes, comments, mentions |
| Media Service | Upload, transcode, serve images/videos via CDN |
Fanout Strategies
| Strategy | Mechanism | Best For | Drawback |
|---|---|---|---|
| Push (on-write) | Pre-compute feeds at write time | Normal users (<10K followers) | Write amplification |
| Pull (on-read) | Compute feed at read time | Celebrities (>10K followers) | High read latency |
| Hybrid | Push + pull combined | Production standard | Complexity in merging |
Storage Choices
| Data | Store | Why |
|---|---|---|
| Posts | MySQL/PostgreSQL + read replicas | Structured, ACID, relational queries |
| Feed cache | Redis Sorted Sets | Sub-ms reads, time-ordered, atomic batch ops |
| Media | S3 + CDN | Object storage + edge caching |
| Search | Elasticsearch | Full-text post search |
| Graph (follows) | Neo4j or adjacency list in MySQL | Relationship queries |
| Events | Kafka | Async processing, event sourcing |
Feed Ranking Signals
| Signal | Weight | Description |
|---|---|---|
| Recency | 0.3 | Exponential time decay |
| Affinity | 0.25 | Interaction frequency with author |
| Engagement Rate | 0.2 | Likes/comments/shares per impression |
| Content Quality | 0.15 | Spam score, text quality |
| Post Type | 0.1 | Video > Photo > Link > Text |
ML Ranking Pipeline
- Candidate Generation (~500 posts from push + pull feeds)
- Feature Extraction (user, post, interaction features)
- Model Scoring (XGBoost / neural network)
- Filtering (blocked users, muted content, already seen)
- Diversification (mix of content types and authors)
- Return top 50 ranked posts
Optimization Strategies
- CDN for media delivery (images, videos, thumbnails)
- Cursor-based pagination for infinite scroll
- Background pre-fetching (next page, images, comments)
- Async processing via Kafka (likes, comments, notifications)
- Rate limiting for viral content
Key Numbers
- 100M posts/day = ~1,160 posts/sec avg
- 7.5B feed reads/day = ~87K reads/sec avg
- Redis feed cache: keep last 1,000 posts per user
- Celebrity threshold: ~10,000 followers
- CDN edge latency: < 50ms vs origin: 200-500ms
Interview Flow
- Requirements (5 min) - functional + non-functional + capacity estimation
- High-level design (10 min) - draw architecture, identify services
- Data model (10 min) - schema, storage selection, why each store
- Deep dive: Feed generation (15 min) - push, pull, hybrid with tradeoffs
- Deep dive: Ranking (10 min) - signals, ML pipeline, real-time vs batch
- Scaling & optimization (10 min) - CDN, caching, handling viral content