System Design · Lesson 7 of 8 · Updated ·
System Design Case Study — Design a Chat App Like WhatsApp
Designing a chat app like WhatsApp tests real-time communication, huge write volume and delivery guarantees. Let's solve it step by step.
Step 1 — Requirements
Functional: one-to-one chat, group chat (up to ~256 members), online/last-seen status, sent ✓ / delivered ✓✓ / read receipts, works when the receiver is offline (deliver later + push notification), media sharing.
Non-functional: very low latency (messages appear instantly), messages never lost, ordered within a chat, end-to-end encryption, works on weak mobile networks.
Step 2 — Estimates
Assume 50 million daily active users, each sending 40 messages a day:
| Quantity | Calculation | Result |
|---|---|---|
| Messages / day | 50 M × 40 | 2 billion |
| Messages / second | 2 B ÷ 86,400 | ≈ 23,000 (peak ≈ 70,000) |
| Text storage / day | 2 B × ~100 bytes | ≈ 200 GB |
| Per year | 200 GB × 365 | ≈ 73 TB (media much more, stored separately) |
This is write-heavy — very different from the URL shortener.
Step 3 — Real-time connection: WebSockets
Normal HTTP is request–response: the server can't push a new message to you. Options:
| Method | How | Verdict |
|---|---|---|
| Polling | ask "any new messages?" every few seconds | wasteful, slow |
| Long polling | server holds the request open until there's news | better, still clunky |
| WebSocket | one persistent two-way connection | ✅ what chat apps use |
Each user keeps a WebSocket to a chat server. A connection registry (in Redis) records which server each online user is connected to.
Step 4 — Message flow (Asha → Ravi)
- Asha's app sends the message over her WebSocket to chat server A.
- Server A stores it (with a unique, time-ordered message id) and acks Asha → ✓ sent.
- Server A looks up Ravi's connection:
- Online on server B → forward to B → B pushes it to Ravi → Ravi's app acks → ✓✓ delivered sent back to Asha.
- Offline → keep it as undelivered and send a push notification (FCM/APNs). When Ravi reconnects, his app fetches pending messages.
- When Ravi opens the chat → read receipt flows back the same way.
Retries + idempotent message ids (the client generates an id) mean a resent message is never shown twice.
Step 5 — Storage
- Access pattern: "give me the latest 50 messages of conversation X", then scroll older. Huge write volume.
- A wide-column store like Cassandra (partition key =
conversation_id, clustering by message time) fits well; WhatsApp-style systems also delete messages from servers once delivered. - Media (photos, videos) go to object storage (S3-like) + CDN; the message just carries a link.
- User profiles, groups, contacts → a regular SQL database.
Step 6 — Groups and presence
- Group message: store once per group; the server fans out delivery to each member's connection/push. For very large groups, fan-out work goes through a queue.
- Presence (online / last seen): clients send heartbeats every ~30 seconds; presence lives in Redis with a short TTL. Only send presence updates to people who have that chat open (otherwise it's a flood).
Trade-offs and extras to mention
- Ordering: guarantee order within a conversation using per-conversation sequence numbers; global order isn't needed.
- End-to-end encryption (Signal protocol): servers store only encrypted blobs.
- Multi-device sync and message search add complexity — mention as follow-ups.
Quick recap
- ~2 B messages/day, ~23K/s average: write-heavy.
- WebSockets for real-time; a registry maps users to chat servers.
- Store → ack (✓) → deliver or push → ack (✓✓) → read receipt.
- Cassandra-like storage by conversation; media in object storage + CDN; Redis for presence.