Mendesain news feed: write fan-out (push model) vs read fan-out (pull model), hybrid approach untuk celebrity accounts, feed service dengan Redis sorted set, dan ranking (recent + relevance) untuk personalisasi feed

Setelah di episode 21 kita mendesain chat system, pada episode ini kita mendesain news feed seperti Twitter/Instagram. News feed adalah salah satu case study paling menarik karena trade-off-nya sangat jelas: setiap posting harus dilihat oleh semua followers — dan beberapa akun punya puluhan juta followers.
Pertanyaan kuncinya: ketika user memposting, apakah kita push posting ke semua followers (fan-out on write), atau followers pull posting saat mereka buka feed (fan-out on read)? Jawabannya: hybrid — dan di episode ini kita bedah kenapa.
Users: 300M DAU
Posts per menit: 1M
Followers per user (rata-rata): 200
Fan-out on write:
1M posts/menit × 200 followers = 200M feed updates/menit
= ~3.3M writes/detik (sangat tinggi!)
Fan-out on read:
500B reads/hari = ~5.8M QPS
Setiap read perlu query posts dari semua followed usersUser A post → save ke DB → push ke feed semua followers
Kelebihan:
- Feed read sangat cepat (pre-computed)
- Tidak perlu compute saat read time
Kekurangan:
- Write amplification: 1 post = 200 feed updates (rata-rata)
- Celebrity problem: 1 post ke 50M followers = 50M writes!
- Storage: setiap user punya copy feedUser B buka feed → query posts dari semua followed users → merge → rank → tampilkan
Kelebihan:
- No write amplification
- Selalu fresh (posts terbaru langsung muncul)
Kekurangan:
- Read sangat lambat: follow 200 orang → 200 queries
- Latency tinggi untuk feed loadingRegular users (<10K followers):
→ Fan-out on write (push ke feed followers)
→ Feed pre-computed, read cepat
Celebrity users (>10K followers):
→ Fan-out on read (pull saat user buka feed)
→ Celebrity posts di-cache, tidak di-push ke semua followers
Feed = pre-computed feed (push) + real-time celebrity posts (pull)1. Client request GET /feed?cursor=X&limit=20
2. Feed service load pre-computed feed dari Redis
3. Load celebrity posts dari cache
4. Merge dan rank (time + relevance)
5. Return paginated feedZADD user:123:feed {timestamp} {post_id}
Feed user 123 = semua post_id di sorted set
Sorted by timestamp (descending)
ZREVRANGEBYSCORE user:123:feed +inf -inf LIMIT 0 20
→ 20 posts terbaruUser A post (regular user, 200 followers):
1. Save post ke DB
2. Fan-out service push ke feed 200 followers
3. Return success
User C post (celebrity, 5M followers):
1. Save post ke DB
2. Simpan ke celebrity cache (TTL 1 jam)
3. TIDAK push ke 5M followers
4. Return successFeed = sorted by created_at DESC
→ Post terbaru di atas1. Affinity: seberapa sering user berinteraksi dengan author
2. Content type: gambar/video lebih tinggi dari text
3. Engagement: likes, comments, shares
4. Freshness: post baru lebih tinggi
5. Controversial: hindari echo chamberscore = (affinity × 0.3) + (engagement × 0.3) + (freshness × 0.25) + (content_type × 0.15)
Dimana:
- affinity: interaction history (0-1)
- engagement: normalized likes+comments+shares (0-1)
- freshness: decay function berdasarkan waktu (0-1)
- content_type: video(1) > image(0.7) > text(0.4)Note
Hybrid approach adalah standar industri untuk news feed. Twitter, Instagram, dan Facebook menggunakan variasi dari push untuk regular users dan pull untuk celebrity accounts. Kunci: pre-compute untuk 99% posts (regular users), real-time compute untuk 1% posts (celebrity).
Inti yang harus dibawa pulang:
Di episode 23 selanjutnya kita akan membahas case study: design distributed rate limiter — token bucket, sliding window, distributed implementation dengan Redis, dan race condition handling. Rate limiter adalah komponen yang melindungi sistem dari abuse dan traffic burst!