System Design Problems interview question · Most asked
Design a chat application (like WhatsApp or Slack).
Summary
Clients keep persistent WebSocket connections to gateway servers; messages are persisted to a partitioned store, then fanned out to online recipients through a pub/sub layer that knows which gateway holds each user's connection, with push notifications for offline users.
Requirements
- 1:1 and group chats (up to ~1,000 members)
- Real-time delivery, message history, delivery/read receipts
- Online presence
- Offline push notifications
- Non-functional: low latency, ordered messages per conversation, durability
Back-of-the-envelope
- 50M daily users × 40 messages ≈ 2B messages/day ≈ 23K/s average
- ~10M concurrent connections → ~200 gateway servers at 50K connections each
API
WS /connect (auth token) → server pushes {type: "message"|"receipt"|"presence", ...}
WS send {"type":"message","conversation_id":"c1","client_msg_id":"uuid","body":"hi"}
GET /api/conversations/{id}/messages?before=<message_id>&limit=50
Data Model
messages(conversation_id, message_id /* time-ordered, e.g. Snowflake */, sender_id, body, created_at,
PRIMARY KEY (conversation_id, message_id)) -- Cassandra/ScyllaDB style
conversation_members(conversation_id, user_id, last_read_message_id)
user_sessions: Redis user_id → gateway_id (with TTL heartbeats)
Architecture
Load balancer → WebSocket gateways (stateful connections only). A gateway forwards incoming messages to a chat service, which assigns a message ID, persists it, and publishes to the recipients via a pub/sub bus (Redis pub/sub or Kafka keyed by user/gateway). Gateways deliver to connected recipients; a notification service sends APNs/FCM pushes to offline ones. Presence uses heartbeats stored in Redis with TTLs.
Deep Dives
- Ordering: per-conversation monotonic IDs; clients sort and dedupe by client_msg_id
- Delivery guarantee: at-least-once with client acks; idempotent storage via client_msg_id
- Group fan-out: fan-out on write for small groups; for large channels, fan-out on read (clients fetch)
- Presence: heartbeat every ~30 s; publish changes only to interested contacts to avoid storms
- E2E encryption: Signal protocol means server stores ciphertext only
Scaling
- Partition messages by conversation_id
- Scale gateways horizontally; route via the session registry
- Rate limit sends; batch receipts
- Multi-region with users homed to a region
Comparison / Tradeoffs
| Decision | Option chosen | Alternative | Why |
|---|---|---|---|
| Transport | WebSockets | Long polling / SSE | Bidirectional, low overhead |
| Message store | Wide-column (Cassandra) | Relational | Write-heavy, partition by conversation, time-ordered scans |
| Group fan-out | Hybrid write/read | Always write | Large channels would explode writes |
Explanation
What interviewers look for
A structured approach: clarify requirements and scale, sketch the API and data model, draw the high-level architecture, then go deep on the hardest component and discuss trade-offs, bottlenecks and failure modes.
Follow-up questions
- How do you sync messages across multiple devices?
- How do you handle a gateway crash?
- How do you implement typing indicators cheaply?
More most-asked System Design Problems questions
- Design a URL shortener (like bit.ly).
- Design a distributed rate limiter.
- Design a social media news feed (like Twitter/X or Instagram).
- Design a notification system (email, SMS, push).
- Design a payment system.
- Design a ticket booking system (like Ticketmaster).
- Design a distributed unique ID generator.
- Design a webhook delivery system.