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

← All System Design Problems questions