High-concurrency chat with Erlang and per-group state
WhatsApp serves billions of users with a small engineering team using Erlang/BEAM, whose lightweight processes map naturally to per-user/per-group message passing. Messages are delivered via a persistent connection; offline messages are stored and pushed on reconnect.
Product constraints
- Huge concurrent connections per server (BEAM excels here).
- Messages must be delivered in order within a chat.
- Offline delivery: store messages, push on reconnect.
- End-to-end encryption; servers don't read message content.
High-level diagram
Request path
- Send. Sender's client sends the message over a persistent connection to their server; the server routes to the recipient's server/group.
- Route. For a group, the server fans out to each member's connection (or stores for offline members).
- Deliver/store. Online members get the message pushed; offline members have it queued and delivered on reconnect.
- Ack. Delivery/read receipts flow back; the message is retained until acknowledged, then eligible for deletion.
Data model
Per-chat message logs (ordered, append-only) keyed by chat id. Offline message queues per user. Minimal metadata (who, when, not content) for routing; content is end-to-end encrypted.
Storage / cache / queue choices
Append-only message logs per chat; offline queues per user.
In-memory per-connection/per-chat state in BEAM processes.
BEAM message passing is the queue; offline messages persist in a store.
Scaling levers
- BEAM lightweight processes map to chats/users, enabling millions of concurrent connections per node.
- Per-chat state in a process avoids shared-state contention.
- Store-and-forward for offline users; deliver on reconnect.
- Keep servers stateless of content (E2EE) to minimize trust surface.
Copy vs skip (for a smaller team)
- Persistent connections with per-chat state.
- Store-and-forward for offline delivery.
- Append-only message logs per chat.
- Minimize server-side content trust (E2EE).
- Erlang/BEAM specifically (use any actor-model or per-connection state) unless you have Erlang expertise.
- Per-message DB writes on the hot path (batch/persist async).
- Centralized routing for all chats (shard by chat id).
Related terms
WebSockets, Event sourcing, Exactly-once delivery, Pub/Sub, Backpressure