Lesson 0033 · System Design · Modul Studi kasus · ±20 menit

Studi kasus: chat (A)

Langkah 1–4: requirement, estimasi pesan dan koneksi, polling vs long polling vs WebSocket, data model per percakapan, dan desain v1

Sebelumnya, lesson 0032 menyelesaikan news feed: sistem read-heavy yang boleh terlambat beberapa detik. Chat berbeda di dua hal: server harus mendorong pesan ke client dalam hitungan ratus milidetik, dan urutan pesan di satu percakapan harus benar. Seperti news feed, soal ini dibagi dua: lesson ini langkah 1–4, lesson 0034 langkah 5.

Target lesson ini: Anda bisa menjawab "Rancang aplikasi chat untuk percakapan 1:1 dan grup kecil, 10 juta DAU" sampai desain v1, tanpa catatan, dalam 90 detik: requirement, QPS pesan dan jumlah koneksi bersamaan, kenapa WebSocket dan bukan polling (dengan angka), tabel pesan yang di-partisi menurut percakapan, dan desain v1 satu chat server.

Langkah 1 — Klarifikasi requirement

Langkah 2 — Estimasi

BesaranHitunganHasil
QPS pesan masuk107 × 40 ÷ 105 detik±4.000 pesan/detik; puncak 3× ≈ ±12.000
Koneksi bersamaan30% × 107±3 juta koneksi pada puncak
Storage4 × 108 pesan × ±200 byte per hari±80 GB/hari ≈ ±29 TB/tahun
Kalau memakai polling3 juta client ÷ polling tiap 2 detik±1,5 juta request/detik, > 99% kosong

Dua angka menentukan soal ini. Baris terakhir menjawab pertanyaan protokol di langkah 3. Baris kedua, 3 juta koneksi yang harus tetap terbuka, menjadi deep dive di lesson 0034. Bandingkan dengan news feed: di sana yang mahal adalah QPS baca; di sini yang mahal adalah koneksi yang hidup lama.

Langkah 3 — API dan data model

Protokol: polling, long polling, atau WebSocket.

Pilih WebSocket untuk kirim dan terima pesan; ini pola yang sama dengan dokumentasi AWS API Gateway: "services can push data to clients without requiring clients to make an explicit request", dan WebSocket API "are often used in real-time applications such as chat applications". [3] Riwayat tetap lewat REST biasa, karena bisa di-cache dan di-paginate.

WebSocket  wss://chat.example.com/v1/ws
  client → server  { "type": "send", "conversationId": "c_17", "clientMsgId": "a1b2…", "text": "halo" }
  server → client  { "type": "ack",  "clientMsgId": "a1b2…", "seq": 5012 }
  server → client  { "type": "message", "conversationId": "c_17", "seq": 5012, "from": 42, "text": "halo" }

REST  GET /v1/conversations/c_17/messages?beforeSeq=5012&limit=50     ← riwayat, cursor = seq

Tabel
  messages            PRIMARY KEY ((conversation_id), seq) — urut seq menurun
                      kolom: sender_id, client_msg_id, text, created_at
  conversation_members (conversation_id, user_id)
  user_conversations   (user_id, conversation_id, last_read_seq)   ← daftar chat + penanda sudah dibaca

Kenapa conversation_id sebagai partition key. Hampir semua query berbentuk "pesan terakhir di percakapan X". Dokumentasi Cassandra: "the first field or component of a primary key is hashed to generate the partition key and the remaining fields or components are the clustering keys that are used to sort data within a partition." [4] Satu percakapan = satu partition, terurut menurut seq. Bentuk key ini sama baiknya untuk PostgreSQL (primary key (conversation_id, seq)) di v1; ±29 TB/tahun baru membenarkan penyimpanan wide-column yang di-partisi, dan pindah ke sana tidak mengubah bentuk key. clientMsgId dibuat client supaya kirim ulang setelah koneksi putus tidak membuat pesan ganda.

Latihan 1 — Protokol dan data model

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.

Langkah 4 — High-level design (v1)

Desain v1 paling sederhana: satu chat server yang memegang semua koneksi WebSocket, plus satu database. Chat server menyimpan peta di memori: user_id → koneksi.

  1. Pengirim mengirim send. Server memberi nomor seq berikutnya untuk percakapan itu, menyimpan pesan, lalu membalas ack. Pesan dianggap terkirim setelah tersimpan, bukan sebelumnya.
  2. Server mencari anggota percakapan di peta koneksi dan mendorong message ke yang sedang terhubung.
  3. Anggota yang offline tidak menerima apa pun saat itu. Ketika terhubung lagi, client mengirim seq terakhir yang ia punya per percakapan, dan server mengirim semua pesan setelahnya dari database.

v1 ini sudah memenuhi semua requirement functional untuk satu server: urutan benar karena satu server memberi semua seq, dan pesan offline tidak hilang karena database menjadi sumber kebenaran. Saat peluncuran (mis. puluhan ribu user online) ini cukup; ukur jumlah koneksi dan memori per koneksi di server itu sebelum menambah apa pun.

Latihan 2 — Gambar diagram v1 sendiri dulu

Gambar diagram v1 Anda sendiri dulu: koneksi mana yang hidup lama, kapan pesan disimpan relatif terhadap ack, dan bagaimana user offline mendapat pesannya. Setelah selesai, buka jawabannya.

Lihat jawaban
User A User B Chat server (1) DB messages 1. send (WebSocket) 3. message (WebSocket) 2. simpan + seq peta: user_id → koneksi (conversation_id, seq)
v1: satu chat server memberi seq, menyimpan, membalas ack ke A, lalu mendorong ke B. B yang offline mengambil pesan setelah seq terakhirnya saat reconnect.

Di mana v1 berhenti cukup. Target skalanya ±3 juta koneksi bersamaan, jauh di atas yang wajar dipegang satu server, dan satu server juga titik gagal tunggal. Begitu ada banyak chat server, muncul empat pertanyaan baru: bagaimana pesan berpindah dari server pengirim ke server penerima, bagaimana tahu siapa yang online, siapa yang memberi seq, dan bagaimana pesan offline sampai ke ponsel yang tertidur.

Latihan lisan — Ucapkan dengan suara keras

Pasang timer dan jawab dengan suara keras, seolah sedang interview. Jangan buka jawaban contoh sebelum selesai.

"Rancang aplikasi chat untuk percakapan 1:1 dan grup kecil, 10 juta DAU. Mulai dari requirement sampai desain v1." (90 detik)
Bandingkan dengan jawaban contoh dan checklist-nya

"Scope-nya pesan teks 1:1 dan grup sampai 100 orang, status online, pesan untuk user offline disampaikan saat ia kembali, riwayat tersimpan di semua perangkat; enkripsi end-to-end dan media di luar scope. 10 juta DAU, 40 pesan per user per hari: sekitar 4.000 pesan per detik, puncak 12.000. Kalau 30% online di puncak, itu 3 juta koneksi bersamaan. Polling setiap 2 detik berarti 1,5 juta request per detik yang hampir semuanya kosong, jadi saya pakai WebSocket untuk kirim dan terima, dan REST untuk riwayat dengan cursor seq. Tabel messages di-partisi menurut conversation_id dengan clustering seq; storage sekitar 80 GB per hari, 29 TB per tahun. Desain v1: satu chat server WebSocket yang memberi seq, menyimpan pesan, lalu mendorongnya ke penerima yang terhubung; penerima yang offline mengambil pesan setelah seq terakhirnya saat reconnect. Batas v1 adalah jumlah koneksi per server; 3 juta koneksi itulah deep dive-nya."

Checklist: apakah Anda menyebut…

  • requirement: 1:1 + grup kecil, presence, pesan offline, riwayat multi-device; yang di luar scope disebut?
  • estimasi: ±4.000 pesan/detik (puncak ±12.000) dan ±3 juta koneksi bersamaan?
  • protokol: WebSocket untuk kirim/terima, dengan alasan biaya polling (±1,5 juta request/detik kosong)?
  • data model: messages dengan partition key conversation_id dan clustering seq; storage ±80 GB/hari?
  • v1: satu chat server WebSocket + database, penerima offline mengambil pesan setelah seq terakhir?
  • membenarkan komponen dengan angka (WebSocket karena biaya polling; batas v1 karena 3 juta koneksi)?

Lulus jika minimal 4 dari 6.

Bacaan lanjutan (opsional, tidak dihitung dalam durasi) RFC 6455: The WebSocket Protocol, bagian 1.1–1.3, ±15 menit. Latar belakang, masalah polling, dan opening handshake.

Desain v1 sudah berdiri, dan angka 3 juta koneksi sudah di tangan. Lanjut di lesson 0034: langkah 5, koneksi WebSocket stateful, presence, ordering, dan pesan offline.

Istilah: GLOSSARY.md (bagian "Studi kasus") · Indeks: semua lesson System Design

Ada yang belum jelas? Tanyakan ke saya (agent) di terminal, misalnya: "kapan Server-Sent Events cukup untuk chat?", "bagaimana grup 100 anggota mengubah estimasi?", atau "kenapa riwayat lewat REST dan bukan WebSocket?"

Sumber: [1] RFC 6202: Known Issues and Best Practices for the Use of Long Polling and Streaming in Bidirectional HTTP · [2] RFC 6455: The WebSocket Protocol · [3] AWS docs: API Gateway WebSocket APIs · [4] Apache Cassandra docs: Introduction to data modeling