Studi kasus: news feed (B): fan-out
Langkah 5: fan-out on write vs fan-out on read, feed cache yang dibatasi, dan hybrid untuk akun besar
Sebelumnya, lesson 0031 mengerjakan langkah 1–4 dan berhenti di satu angka: ±600.000 pencarian index per detik pada puncak. Lesson ini adalah langkah 5: setiap komponen baru harus menjawab angka itu, atau angka baru yang muncul dari komponen sebelumnya.
Ringkasan dari lesson 0031
Langkah 5 — Deep dive: fan-out on write vs fan-out on read
Langkah ini adalah evolusi dari v1 ke v2, satu perubahan per masalah yang terlihat di angka:
1. Fan-out on write: siapkan feed sebelum dibaca. Saat post dibuat, ID-nya ditambahkan ke feed setiap follower. Membaca feed tinggal mengambil satu list. Redis mendokumentasikan pola ini sendiri: salah satu kegunaan list adalah "Remember the latest updates posted by users into a social network." [1] Perbandingannya dalam angka:
| Fan-out on read (v1) | Fan-out on write | |
|---|---|---|
| Kerja saat post dibuat | 1 INSERT | 1 INSERT + 200 penulisan feed (±20.000/detik, puncak ±60.000) |
| Kerja saat feed dibuka | 200 rentang index (±600.000/detik pada puncak) | 1 baca list (±3.000/detik pada puncak) |
| Post baru terlihat | langsung | beberapa detik kemudian (diizinkan di langkah 1) |
| Unfollow, hapus post | otomatis benar | perlu dibersihkan atau disaring saat baca |
Sistem ini read-heavy 10:1, jadi memindahkan kerja dari baca ke tulis adalah pertukaran yang menguntungkan. Untuk sistem dengan rasio sebaliknya, v1 tetap lebih baik.
2. Feed cache yang dibatasi. Simpan hanya ID post, bukan isinya, dan batasi panjangnya: "Redis allows us to use lists as a capped collection, only remembering the latest N items and discarding all the oldest items using the LTRIM command." [1]
Worker menjalankan LPUSH feed:42 9001 lalu LTRIM feed:42 0 799. Estimasi: 800 ID × 8 byte × 10 juta user ≈ 64 GB, cukup untuk beberapa node Redis yang di-shard menurut user_id.
Isi post diambil saat baca dari cache post (satu post dibaca banyak follower, cocok untuk cache) atau dari database. Karena isi tidak disalin, post yang dihapus cukup disaring saat itu.
User yang menggulir melewati 800 ID jatuh ke query v1; itu jarang, dan v1 tetap benar.
3. Fan-out asinkron lewat queue. 200 penulisan per post tidak boleh membuat POST /v1/posts menunggu. Post service menyimpan post, mengirim event ke queue, lalu langsung membalas 201.
Worker fan-out membaca daftar follower (index followee_id dari lesson 0031) dan menulis ke feed cache. Dengan Kafka, event diberi key author_id:
"Events with the same event key (e.g., a customer or vehicle ID) are written to the same partition, and Kafka guarantees that any consumer of a given topic-partition will always read that partition's events in exactly the same order as they were written." [2]
Jadi post dari satu penulis masuk ke feed dalam urutan yang benar, dan worker bisa ditambah sampai sejumlah partition.
4. Hybrid untuk akun besar. Fan-out on write murni gagal di ujung distribusi: satu post dari akun dengan 10 juta follower menjadi 10 juta penulisan, dan post lain menunggu di belakangnya. Hybrid: akun di atas ambang (mis. 10.000 follower) tidak di-fan-out. Saat user membuka feed, app server mengambil feed cache-nya, lalu mengambil post terbaru dari sedikit akun besar yang ia follow (query v1, tetapi hanya untuk beberapa penulis, bukan 200), dan menggabungkan keduanya menurut waktu. Post terbaru akun besar dibaca jutaan kali, jadi simpan di cache. Ambangnya bukan angka ajaib: ukur antrean fan-out dan latensi baca, lalu geser ambang sampai keduanya dalam target.
5. Jangan fan-out ke user yang tidak membaca. Kalau sepertiga follower tidak login berbulan-bulan, sepertiga penulisan dan memori terbuang. Fan-out hanya ke user aktif (mis. login 30 hari terakhir). Saat user lama kembali, feed-nya dirakit sekali dengan fan-out on read, lalu cache diisi lagi.
Latihan 1 — Gambar diagram v2 sendiri dulu
Gambar diagram v2 Anda sendiri dulu, mulai dari v1 di ringkasan: di mana queue, worker fan-out, dan feed cache berada, dan dari mana post akun besar diambil saat baca. Setelah selesai, buka jawabannya.
Lihat jawaban
Jalur tulis: POST → simpan post → event ke queue (key author_id) → 201. Worker: kalau penulis di bawah ambang, baca follower aktif → LPUSH + LTRIM per follower.
Jalur baca: LRANGE feed:me 0 19 + post terbaru akun besar yang di-follow → gabung menurut waktu → ambil isi post dari cache post → 20 post + cursor.
Latihan 2 — Fan-out dan hybrid
Jawab tanpa scroll ke atas. Soal yang sama akan muncul lagi, diacak, di review 0035.
Kuis di lesson ini adalah feedback cepat, bukan bukti penguasaan; yang dicatat hanya hasil review 0035.
Latihan lisan — Ucapkan dengan suara keras
Pasang timer dan jawab dengan suara keras, seolah sedang interview. Jangan buka jawaban contoh sebelum selesai.
"Desain v1 news feed Anda fan-out on read. Di 10 juta DAU, dengan akun terbesar 10 juta follower, bagaimana Anda mengembangkannya?" (90 detik)
Bandingkan dengan jawaban contoh dan checklist-nya
"Di v1, satu pembukaan feed menyentuh 200 penulis, jadi pada puncak 3.000 feed per detik itu sekitar 600.000 pencarian index per detik. Evolusi pertama: fan-out on write. Post disimpan, lalu event-nya masuk queue; worker menambahkan ID post ke feed cache setiap follower di Redis, dengan LTRIM supaya hanya 800 ID terakhir, sekitar 64 GB untuk 10 juta user. Membaca feed tinggal satu key. Biayanya 100 post kali 200 follower, sekitar 20.000 penulisan per detik, dan post muncul beberapa detik kemudian, yang diizinkan requirement. Masalahnya akun besar: satu post jadi 10 juta penulisan. Jadi saya pakai hybrid: akun di atas ambang, misalnya 10.000 follower, tidak di-fan-out; post terbarunya diambil saat feed dibaca dan digabung dengan feed cache. Saya juga hanya fan-out ke user yang aktif 30 hari terakhir; user lama dirakit dengan fan-out on read saat kembali."
Checklist: apakah Anda menyebut…
- titik awal: biaya v1 ±600.000 pencarian index/detik pada puncak?
- fan-out on write: queue + worker menulis ID post ke feed cache setiap follower?
- feed cache terbatas (LTRIM, mis. 800 ID) dengan estimasi memori?
- biaya fan-out on write: ±20.000 penulisan/detik dan keterlambatan beberapa detik yang diizinkan?
- hybrid: akun besar di atas ambang diambil saat baca; user tidak aktif tidak di-fan-out?
- membenarkan komponen dengan angka (cache karena 600.000/detik; hybrid karena 10 juta penulisan per post)?
Lulus jika minimal 4 dari 6.
Berikutnya, lesson 0033: chat, langkah 1–4.
Istilah: GLOSSARY.md (bagian "Studi kasus") · Indeks: semua lesson System Design
Ada yang belum jelas? Tanyakan ke saya (agent) di terminal, misalnya: "bagaimana menghapus post dari feed cache setelah unfollow?", "bagaimana feed berubah kalau ada ranking?", atau "bagaimana menentukan ambang akun besar dengan metrik?"
Sumber: [1] Redis docs: Lists (capped lists, LTRIM) · [2] Apache Kafka 4.4 docs: Introduction, main concepts