THN Interview Prep

Design WhatsApp (Messaging)

1. Requirements

Functional

  • 1:1 and group chat with delivery receipts (single/double check semantics product-dependent), read receipts optional.
  • Multimedia messages: images, voice notes, documents uploaded through encrypted references.
  • Online/presence and typing indicators with low staleness.
  • Push notifications when app backgrounded using FCM/APNs with encrypted payload limitations handled by wake-and-fetch pattern.
  • End-to-end encryption (E2EE): server must not read plaintext message bodies — Signal Protocol (Double Ratchet) widely referenced in interviews.

Non-Functional

  • Scale: 2B+ users class globally; peak message rate in tens of millions per second aggregate across regions (order-of-magnitude teaching).
  • Latency: sub-second delivery expectation on same continent; typing indicator <200 ms server RTT budget.
  • Availability: 99.99% message acceptance; partitioned tolerance across regions with queue-based eventual delivery.
  • Consistency: per-chat ordering stronger than global; CAP favors availability + partition tolerance with ordering fixes client-side when rare anomalies occur.

Out of Scope

  • Full Double Ratchet cryptographic specification step-by-step (state high level).
  • Payments and commerce rail depth.
  • Server-side content moderation of E2EE bodies (metadata-only strategies).
  • Large group video conferencing architecture (focus async messaging).

2. Back-of-Envelope Estimations

Assume 2B monthly actives, 100B messages/day global ballpark for teaching scale.

  • Messages/s: 100B / 86,400 ~ 1.16M/s average; peak factor 3–5x3–6M/s — requires massive sharded messaging plane.

  • Average message envelope 200 B ciphertext + routing metadata — metadata plane 200 MB/s average without media; media separate object path dominates bandwidth.

  • Storage: Text-only retention policies vary; 30-day server-side vs delete-on-delivery — WhatsApp-like minimal server retention shifts storage to clients — server stores undelivered queue only briefly.

  • Presence updates: If each user heartbeat every 30s → 2B / 30 ~ 66M updates/min worst case — must aggregate/coalesce; realistic push-based presence changes only on app foreground transitions → far lower.


3. API Design

Conceptual binary protocol (WhatsApp uses custom); REST shown for clarity.

POST /v1/sessions
Body: { "devicePublicKey": "...", "identityProof": "..." }
-> 201 { "sessionToken": "...", "wsEndpoint": "wss://edge.example/v1/ws" }
POST /v1/messages
Authorization: Bearer <token>
Body: {
  "chatId": "c_abc",
  "clientMsgId": "uuid",
  "ciphertext": "<base64>",
  "type": "text"
}
-> 202 { "serverMsgId": "sm_123", "timestamp": "..." }
GET /v1/chats/{chatId}/history?since=cursor
-> 200 { "messages": [ ... ] }  // ciphertext blobs if server stores temporarily

WebSocket primary for delivery:

Server -> Client: { "event": "message", "chatId": "...", "ciphertext": "..." }

gRPC streaming alternative for mobile efficiency.


4. Data Model

Chat session

  • chat_id, type (direct|group), participants many-to-many table.

Message record (server-visible fields only)

  • server_msg_id, chat_id, sender_device_id, ciphertext_blob_ref or inline blob in Cassandra for short retention, timestamp, delivery_state.

Device

  • user_id, device_id, registration_id for Signal protocol, push_token for FCM/APNs.

Why Cassandra / Scylla for message routing

  • Horizontal partition by chat_id clusters messages; time-series friendly — vs DynamoDB similar.

Why not Postgres for hot path

  • Single-row writes per message at million/s scale exceed vertical limits — sharded SQL possible with expertise (consistent hashing on chat_id).

Object storage

  • Media ciphertext uploaded presigned S3; message row holds pointer + MAC metadata.

Sample row

chat_idserver_msg_idsenderciphertext_handlets
c42991823...d7s3://blob...

5. High-Level Architecture

Loading diagram…

Cross-region: message queues for eventual replica sync; presence via caching layer.


6. Component Deep-Dives

Connection layer

  • WebSocket sticky sessions on L4/L7 load balancer — reconnect storms handled with jittered backoff client-side.
  • MQTT alternative for IoT-friendly semantics — WhatsApp-class historically custom frames over TLS.

Message routing

  • Hash chat_id → shard Kafka topic partition or directly to Cassandra writer pod pool — single writer per chat avoids ordering races within chat.

E2EE responsibilities

  • Server routes opaque ciphertext; key exchange via X3DH at session setup — stored device keys in low-read KV with privacy-preserving directory (ID generation for device ids).

Delivery receipts

  • Small ack messages piggyback on same socket; offline acks queue until reconnect.

Push notifications

  • No plaintext in FCM data payload if strict — send encrypted envelope id; client wakes, pulls full message via WebSocket.

Group chats

  • Sender keys broadcast via pairwise channels — operational complexity; scale group size limits.

Media

  • Client uploads ciphertext to S3; separate integrity verification — parallel to Instagram infra without server-side decode.

Why Kafka in messaging

  • Cross-datacenter replication and buffering during partial outages — alternative RabbitMQ shovel less common at this throughput.

7. Bottlenecks & Mitigations

BottleneckSymptomMitigation
Hot chat (world cup group)Partition hot shardSplit rarely; fan-in careful sequencing single writer
Presence stampedeRedis overloadSample presence; aggregate friend visibility bucketing
Reconnect stormGateway CPURate limit handshakes; regional DNS shuffle
Push token invalidWasted provider quotaPrune on bounce webhook
Cross-region latencyHigher delivery delayUser affinity to nearest DC where legally possible

8. Tradeoffs

DecisionAlternativeWhy we picked
Cassandra message storeSharded MySQLWrite throughput path clarity
WebSocket long-livedHTTP pollingBattery and latency unacceptable
Minimal server retentionFull history cloudE2EE trust + cost model
Kafka cross-regionDB replication onlyDecouple failures + replay
E2EE defaultServer readableProduct privacy stance
Binary custom protocolJSON RESTBandwidth and parse CPU on mobile

9. Follow-ups (interviewer drill-downs)

  • Offline-first: Client SQLite queue; merge conflicts rare in messaging vs CRDT docs.
  • Multi-device: Each device has separate ratchet state; message fan-out to all user devices.
  • Spam without plaintext? Rate limits by metadata (distributed rate limiter), behavioral signals, user reports.
  • Lawful intercept tension: Product/legal outside engineering scope but acknowledge metadata availability.
  • LLD: Wire format versioning and backwards compatibility during rolling upgrades.

Last updated on

Spotted something unclear or wrong on this page?

On this page