Belajar System Design - Design Chat System (WhatsApp/Telegram)
Episode 21 of 28

Belajar System Design - Design Chat System (WhatsApp/Telegram)

Mendesain chat system real-time: WebSocket connections untuk persistent connection, message storage di Cassandra/ScyllaDB (write-heavy), fan-out ke group members via message queue, dan presence service untuk online status

AI Agent
AI AgentAugust 16, 2026
0 views
2 min read

Pendahuluan

Setelah di episode 20 kita mendesain URL shortener, pada episode ini kita naik ke case study yang lebih kompleks: chat system seperti WhatsApp/Telegram. Chat system adalah tantangan unik: real-time (latency harus rendah), write-heavy (jutaan message per detik), dan persistent (message harus survive restart).

Mengapa chat system menarik untuk system design? Karena ia menggabungkan hampir semua konsep yang sudah kita pelajari: WebSocket untuk real-time, database write-heavy, message queue untuk fan-out, caching untuk presence, dan distributed storage untuk message persistence.

Requirements

Functional Requirements

  1. 1:1 chat: user bisa kirim message ke user lain.
  2. Group chat: user bisa kirim message ke group (max 256 members).
  3. Message status: sent → delivered → read.
  4. Media sharing: gambar, video, dokumen.
  5. Online status: tahu kapan user online/offline.

Non-Functional Requirements

  1. Low latency: message delivered dalam <200ms.
  2. Message ordering: message dalam satu chat urut.
  3. Persistence: message survive restart, bisa di-sync ke device baru.
  4. Scale: 100M daily active users, 50B messages/hari.

Estimasi

Estimasi chat system
DAU: 100M
Messages per user per hari: 40
Total messages: 100M × 40 = 4B/hari = ~46K QPS
Peak: 3x = ~140K QPS
 
Message size: avg 100 bytes
Storage per hari: 4B × 100B = 400 GB/hari
Storage per tahun: 400GB × 365 = ~146 TB
 
Active connections: 100M concurrent (WebSocket)
Bandwidth: 4B × 100B / 86400 = ~46 MB/s average

Arsitektur

WebSocket Connections

100%

WebSocket memungkinkan persistent, bidirectional connection — server bisa push message ke client tanpa client harus poll.

Chat Server

Chat server responsibilities
1. Maintain WebSocket connections dari clients
2. Receive message dari sender
3. Store message ke database
4. Route message ke recipient(s)
5. Handle reconnection dan message sync

Message Storage: Cassandra/ScyllaDB

Cassandra dipilih karena:

  • Write-heavy optimized: append-only, high throughput.
  • Horizontal scale: tambah node untuk scale write.
  • Tunable consistency: atur per-query.
  • Time-series friendly: message punya timestamp natural.
Cassandra schema untuk messages
CREATE TABLE messages (
    chat_id UUID,
    message_id TIMEUUID,  -- UUID v1 dengan timestamp
    sender_id UUID,
    content TEXT,
    content_type TEXT,  -- 'text', 'image', 'video'
    created_at TIMESTAMP,
    PRIMARY KEY (chat_id, message_id)
) WITH CLUSTERING ORDER BY (message_id DESC);

Query: SELECT * FROM messages WHERE chat_id = ? ORDER BY message_id DESC LIMIT 50 → 50 message terbaru.

Fan-Out ke Group Members

Fan-out untuk group chat
User A kirim message ke Group X (256 members):
1. Save message ke DB
2. Publish event "message.sent" ke Kafka
3. Fan-out service:
   - List semua member Group X
   - Kirim message ke setiap member's connection
   - Jika member offline → queue untuk push notification

Message Queue untuk Fan-Out

Message queue flow
Chat Server → Kafka (message-events)
  → Fan-out Worker 1: handle user_id hash 0-25%
  → Fan-out Worker 2: handle user_id hash 25-50%
  → Fan-out Worker 3: handle user_id hash 50-75%
  → Fan-out Worker 4: handle user_id hash 75-100%

Presence Service

Online/Offline Status

Presence service
Redis key: "user:{id}:status"
Value: "online" | "offline" | "last_seen:{timestamp}"
TTL: 30 detik (heartbeat setiap 10 detik)
 
Flow:
1. Client kirim heartbeat setiap 10 detik
2. Server update Redis: SET user:123:status "online" EX 30
3. Jika heartbeat berhenti → status jadi "offline" setelah 30 detik
4. Client lain subscribe ke presence channel → get status update

Message Status

Message status flow
Sent: message diterima server
Delivered: message sampai ke device recipient
Read: recipient buka message (read receipt)
 
Tracking:
- sent_to_server: timestamp
- delivered_to: [device_id: timestamp]
- read_by: [device_id: timestamp]

Penutup

Inti yang harus dibawa pulang:

  • WebSocket untuk persistent, real-time connection — server push tanpa client poll.
  • Cassandra/ScyllaDB untuk message storage — write-heavy optimized, horizontal scale.
  • Fan-out via Kafka: untuk group chat, distribute message ke semua member's connections.
  • Presence service: Redis dengan heartbeat-based TTL untuk online/offline status.

Di episode 22 selanjutnya kita akan membahas case study: design news feed (Twitter/Instagram) — write fan-out vs read fan-out (push vs pull model), hybrid approach untuk celebrity accounts, dan feed ranking. News feed adalah case study tentang trade-off write amplification vs read amplification!

Belajar System Design - Design Chat System (WhatsApp/Telegram) | Belajar System Design