Security Notes
System Design

Design WhatsApp (Chat System)

5 min read 7 sections

DifficultyMedium | HelloInterview: problem breakdown


Problem Statement

Design a real-time messaging system supporting 1-on-1 and group chats. Messages should be delivered reliably, with delivery/read receipts, and users should see typing indicators.

๐Ÿ“–

Real-world: WhatsApp is the other famous "absurd scale per engineer" story โ€” in 2014 it served 450M users with ~32 engineers, built on Erlang (whose lightweight processes and battle-tested telecom heritage are ideal for millions of persistent connections), reportedly pushing ~2M+ TCP connections per server. The design lesson is that chat is fundamentally about long-lived connections + a fan-out/delivery problem, not request/response โ€” hence WebSockets and per-user inboxes. For a security audience the headline is end-to-end encryption: WhatsApp adopted the Signal Protocol (Double Ratchet), which means the server relays ciphertext it can't read โ€” a profound design constraint, because features people expect (server-side search, multi-device sync, abuse scanning) all become hard when the server is blind. That tension between E2EE and trust-and-safety is a great thing to raise.


Requirements

Functional

  • 1-on-1 messaging
  • Group chats (up to 512 members)
  • Message delivery/read receipts (โœ“ sent, โœ“โœ“ delivered, โœ“โœ“ read)
  • Online presence indicators
  • Typing indicators
  • Media sharing (images, files)
  • Message history

Non-Functional

  • 2B users, 100M DAU
  • 50 messages/day/user โ†’ 50B messages/day โ†’ 578k messages/s
  • P99 message delivery latency: < 500ms
  • Messages stored forever (or configurable retention)
  • End-to-end encryption (E2EE)

Core Design

Connection Layer โ€” WebSocket

HTTP is request/response โ€” server can't push without client polling. For real-time messaging, use WebSockets (persistent bidirectional TCP connection).

Client A โ”€โ”€WebSocketโ”€โ”€โ†’ Chat Server A
Client B โ”€โ”€WebSocketโ”€โ”€โ†’ Chat Server B
                    โ†‘
          Chat Server A โ†’ Message Queue โ†’ Chat Server B โ†’ Client B

Each user connects to one chat server. Chat servers are stateful (maintain WebSocket connections). A message routing layer (pub/sub or a message queue) connects chat servers.

Message Flow

1. Client A sends message via WebSocket to Chat Server A
2. Chat Server A:
   a. Persist message to Message DB
   b. Publish to pub/sub channel for conversation_id
3. Chat Server B (where Client B is connected) receives from pub/sub
4. Chat Server B delivers message to Client B via WebSocket
5. Client B sends "delivered" ACK
6. Chat Server B updates message status, notifies Client A

Offline Message Delivery

If recipient is offline:

  1. Message persisted to DB
  2. Push notification sent (APNs/FCM)
  3. On next connection, client fetches unread messages

Architecture

             Load Balancer (sticky sessions / consistent hash by user_id)
                    โ†“
           Chat Server Cluster (WebSocket servers, stateful)
                    โ†“
            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
            โ”‚                               โ”‚
     Message Queue (Kafka)         Presence Service (Redis)
            โ”‚                               โ”‚
     Message DB (Cassandra)       Group Service
            โ”‚
     Media Store (S3 + CDN)

Database Design (Cassandra)

Cassandra is ideal: massive write throughput, time-series access pattern per conversation.

messages(
  conversation_id  UUID,
  message_id       BIGINT,     -- Snowflake timestamp-based for ordering
  sender_id        UUID,
  content          TEXT,       -- encrypted blob
  message_type     ENUM,       -- text, image, video, etc.
  created_at       TIMESTAMP,
  status           ENUM,       -- sent, delivered, read
  PRIMARY KEY (conversation_id, message_id DESC)
)

Conversation ID

  • 1-on-1: min(user_a, user_b) + max(user_a, user_b) โ†’ deterministic, no coordination
  • Group: generated UUID at group creation

Presence Service

Redis:
  online:{user_id} โ†’ last_heartbeat_timestamp (TTL 30s)
  • Client sends heartbeat every 10s
  • If key expired โ†’ user is offline
  • Typing indicators: typing:{conversation_id}:{user_id} with 5s TTL

Group Messaging at Scale

For groups of 512 members, fan-out on write would mean 512 WebSocket pushes per message. This is manageable at small group size.

For super-groups (thousands of members) โ†’ fan-out on read: server fetches new messages on client reconnect / scroll.


End-to-End Encryption (E2EE)

WhatsApp uses the Signal Protocol:

Key generation

each client generates a key bundle (identity key, signed pre-key, one-time pre-keys)

Key exchange

server stores public key bundles; clients fetch recipient's bundle to establish shared secret

Message encryption

each message encrypted with session key derived from X3DH + Double Ratchet

Server never sees plaintext

stores only encrypted blobs

Key Registration:
  Client โ†’ Upload public key bundle โ†’ Key Server

Message Send (Client A โ†’ Client B):
  1. Fetch Client B's public key bundle from Key Server
  2. Perform X3DH key agreement โ†’ shared secret
  3. Encrypt message with shared secret (AES-256-GCM)
  4. Send encrypted ciphertext to Chat Server
  5. Chat Server stores + routes ciphertext
  6. Client B decrypts with their private key

Design implicationserver cannot read messages, cannot provide message search across all conversations, cannot provide server-side spam filtering of message content.


Security Considerations

ThreatMitigation
Message interceptionE2EE (Signal Protocol); server only sees ciphertext
Account takeover2FA (SMS + TOTP); device registration approval
Spam / unsolicited messagesRate limit messages per sender; block/report; ML on metadata patterns
MITM during key exchangeKey verification via safety numbers (QR code comparison)
Malicious media (malware in attachments)Client-side scanning; server-side hash check against known malware DB
WebSocket DDoSRate limit connection attempts; require auth before WebSocket upgrade
Group member enumerationGroup membership hidden from non-members
Session fixationNew session keys on each device registration; session revocation on logout

Interview Tips

WebSocket vs HTTP polling

explain why WebSocket is the right choice, then explain what happens when WebSocket fails (polling fallback / reconnect with exponential backoff).

Offline delivery is a must

don't forget push notifications for offline users.

E2EE design

interviewers at security-conscious companies will probe this. Key points: Signal Protocol, server stores ciphertext, key bundles, forward secrecy via Double Ratchet.

Cassandra data model

justify the partition key choice (conversation_id) and why it optimizes the read pattern (fetch messages for a conversation, ordered by time).