Requirements and Scale
Functional: users see a ranked, paginated feed of posts from friends and followed pages, including photos, videos, text, and shared links. Feed is personalized — ranked by a relevance score. Non-functional: high availability, low latency (< 2s to render feed), eventual consistency for feed updates is acceptable.
Scale: 2B monthly active users, 500M daily active. Average user has 300 friends. 300M posts per day ≈ 3,500 posts/sec. Feed reads: 5M/sec (users refreshing feed constantly).
Feed Generation: Fanout on Write vs Read
Fanout on write (push): when a user posts, immediately push the post to each of their friends' news feed caches. O(N) writes per post where N = friend count. Fast reads (pre-built cache). Problem: for users with 5,000 friends, one post = 5,000 cache writes. For celebrities (pages with millions of followers): impractical.
Fanout on read (pull): on each feed request, query the posts of all friends, rank them, return top-K. No pre-computation. Very slow at scale — must query hundreds of shards per request.
Facebook hybrid: push posts from regular users into friends' feed caches. For celebrity pages and users with very high fan counts, skip the push — merge their posts at read time by looking up the user's subscriptions and fetching recent posts.
graph TD
Post["User posts"] --> FanoutSvc["Feed Fanout Service"]
FanoutSvc --> Check{Many followers?}
Check -->|No: push| FeedCache["Friends' Feed Caches
(Redis)"]
Check -->|Yes: skip push| CelebDB["Celebrity Posts DB"]
FeedRead["Feed Read API"] --> FeedCache
FeedRead --> CelebDB
FeedRead --> RankEngine["Ranking Engine"] Feed Ranking
Raw chronological feed is not optimal — users care more about posts from close friends than from acquaintances they friended years ago. Facebook's EdgeRank (original algorithm) uses three signals per post: affinity (how close are you to the poster), weight (photos rank higher than link shares), and time decay. Modern feed ranking is a deep neural network trained on billions of user interactions (likes, comments, clicks, share time) with hundreds of features. The ranking model scores each candidate post and returns the top-K.
Feed Aggregation Service
The Feed Aggregation Service is responsible for assembling a user's feed at read time: (1) Fetch pre-built feed from Redis cache (contains post_ids pushed by fanout). (2) Merge with celebrity/page posts (pulled). (3) Fetch full post details for the top-K post_ids (from post shards). (4) Pass through ranking model. (5) Return ranked feed to client. The aggregation service keeps a cursor (last seen post_id) to support pagination.
Caching Architecture
Three cache layers: (1) Feed cache (Redis sorted set per user): stores post_ids in score order. Read-through with TTL. (2) Post cache (Memcached): stores full post objects. Most posts are read many times but written once — high cache hit rate. (3) Social graph cache: stores friend list per user to speed up fanout. Without caching, fetching the friend list from DB on every post would be too slow.
Cache invalidation: when a post is deleted or hidden, remove it from affected feed caches. Use a lazy invalidation strategy: check validity at read time and filter stale entries rather than eagerly scanning all caches.
Media and Notifications
Photos and videos are stored in S3 and served via CDN (same as Instagram). A separate Notification Service handles real-time delivery of likes, comments, and new post alerts via WebSocket or push notification. The notification service is separate from the feed service — it uses its own fan-out mechanism to alert users immediately.