Design WhatsApp
High-concurrency instant messaging service with offline delivery queues and presence indicators.
1. System Requirements
- Real-time one-on-one instant text messaging.
- Delivery indicators (sent, delivered, read status).
- Presence indicator (online, offline, last seen status).
- Group chat support with up to 1,000 members.
- Extremely low latency message delivery (< 200ms).
- Highly durable message delivery guarantees.
- Scales to billions of active messaging connections.
2. Scale & Resource Estimates
Throughput: 2 Billion Total Users. 100 Billion Messages per day = 1.15 Million messages/sec average. Peak = 3 Million messages/sec.
Storage & RAM: 100B messages/day * 100 bytes = 10 Terabytes/day. Retained in chat history partitions.
3. System API Endpoints
// 1. Establish websocket connection
WS /chat/connect?user_id=usr-5012
// 2. Message Payload JSON
{
"message_id": "msg-889342",
"recipient_id": "usr-1102",
"type": "text",
"content": "Hello, see you at 5!",
"timestamp": 1783708872
}
4. Database Schema Design
Table: messages (Cassandra Column Family - Sharded by chat_id)
- chat_id (UUID - Partition Key)
- message_id (TimeUUID - Clustering Key)
- sender_id (UUID)
- content (text)
- status (ENUM: sent, delivered, read)
Table: presence (Redis Cache - Key-Value)
- user_id (Key)
- last_active_timestamp (Integer)
- status (ENUM: online, offline)
5. Interactive High-Level Architecture
6. Scalability Deep Dive & Bottlenecks
Every active user maintains a persistent TCP connection via WebSockets. WebSocket Manager nodes keep track of active sessions in a shared Redis Session Registry. When a message is sent, the routing service checks the registry. If the user is offline, it stores the message in Cassandra and triggers mobile push notifications (FCM/APNS). Online status triggers pub/sub updates to followers' chat channels.
7. Production Scaling Strategies
WebSocket Connection Scaling: 2B users × 30% concurrent = 600M active connections. Run 60K WebSocket gateway nodes (10K connections each). Use consistent hashing on user_id for sticky routing. Gateways are stateless — session state lives in Redis.
Cassandra Partition Sizing: Partition messages by chat_id with TimeUUID clustering. Keep partitions under 100MB (~500K messages). For group chats, sub-partition by time bucket (weekly) to avoid wide partition anti-patterns.
Message Routing Fan-out: Group messages (up to 1000 members) fan out via Kafka topic per-group. Each WebSocket gateway subscribes to its assigned user partitions. Avoids O(N) push from a single node — Kafka handles the fan-out.
Presence System: Track online/offline in Redis with TTL-based heartbeats (30s). Presence updates are published via Redis Pub/Sub to subscribed contacts. Limit presence fan-out to mutual contacts only (not all 2B users) to bound write amplification.
Offline Message Queue: When a user reconnects, pull undelivered messages from Cassandra ordered by timestamp. Batch-deliver in chunks of 100. Mark as 'delivered' via async Kafka event to update sender-side delivery receipts.
Multi-Region: Deploy WebSocket gateways per-region (US, EU, Asia). Messages between regions route through dedicated Kafka MirrorMaker cross-region bridges. User-to-gateway affinity based on nearest PoP via GeoDNS.
8. Runnable Production Starter Code
Scaffold