The problem
"Design Facebook Messenger." It looks like Design WhatsApp, and most of that design carries over. The difference is that people are signed in on several devices at once: a phone, a laptop, a browser tab at work. Every message, every "Seen" and the whole history must look the same on each, and a laptop that was closed for a week must catch up exactly.
This practice problem reuses the pattern of Design Chat (WhatsApp). The decisions go to what several devices change: how each device catches up, what "Seen" means, what typing costs, and how years of history are searched. Park calls, reactions, stories and payments.
The numbers
From the interviewer, as in Chat: about 1 million messages a second at busy hours. Say everyone is signed in on 3 devices.
what worked out about
devices per message Ben's 3 + Ana's other 2 5 (one-to-one)
deliveries 1 million messages × 5 5 million a second
log entries 1 million × 2 members 2 million a second
The sender's own devices are the surprise: Ana's laptop must show what she sent from her phone. Groups multiply it again: a message to 6 people with 3 devices each goes to 17 devices.
Catching up: a numbered log per person
In Chat, a message was marked delivered when the other phone acked it. With several devices that breaks: Ana's phone acks, the message is marked delivered, and her laptop, closed since yesterday, is never sent it. Asking each of her 200 chats for "anything newer" when the laptop opens is no better: 200 reads, nearly all empty, and a chat started while it was closed is missed.
Instead, give each person one numbered log. Every message to or from Ana, and every change to one such as a deletion, gets the next number in her log. Each device keeps a cursor, the last number it has, as in Dropbox, and asks for everything after it:
device cursor asks for gets
phone 1,240 after 1,240 nothing: up to date
laptop 1,204 after 1,204 36 entries, 1,205 to 1,240, in order
The cursors are the delivery state, one per device. Online devices also get each new entry pushed down their WebSocket and move their cursor as they take it. Each message costs one log entry per member: 2 for a one-to-one chat.
"Seen" per person, not per device
Ben reads Ana's "Dinner at 8?" (m205) on his laptop while his phone stays in his pocket. Ana cares whether Ben saw it, not on which screen, so "Seen" appears once any of his devices has read it. Waiting for all of them would mean waiting forever for an old tablet in a drawer, and a Seen per device tells Ana more than Ben may want.
The server keeps one read marker per person per chat: "Ben has read c42 up to m205". It only moves forward, so a device that opens an older message later can't move it back. The marker goes to Ana's devices, which show Seen, and to Ben's phone, which clears its unread badge: one row per member of the chat, not a flag on every message for every device.
Typing: passed on, never stored
A message, a read marker or a deletion must still be known tomorrow, so each is stored and gets a number in every member's log. "Ana is typing…" is useless a few seconds later. The server passes it straight to the devices that have the chat open and drops it: no database, no log. Each device shows the indicator for a few seconds unless a fresh one arrives, so a laptop that dies mid-word doesn't leave "typing…" up for good.
Searching years of history
History is kept forever, partitioned by chat and sorted by message id, as in Tables From Query Patterns: right for "the newest 50 in this chat", useless for a word. Finding "dinner" by reading Ana's 200 chats would read 6 years of messages on every search.
So each saved message is also added to a search index, each word pointing to the messages that contain it, one index per person, filled a moment later off a queue so sending stays fast. A search is one lookup in Ana's index; the price is a group message indexed once per member. One caveat: Meta began making end-to-end encryption the default for personal Messenger chats in late 2023, and then the servers can't read the text, so search has to run on each device. In the interview, say which one you are designing.
Same pattern as Chat (WhatsApp)
The connection layer carries over unchanged: a WebSocket from each online device to a connection server, a session store with one entry per device, a chat service that saves every message before sending it on, and push notifications for devices that are offline. What changed is that a person is no longer one phone, so delivery, receipts and history are kept per device and per person.
Summary
- Scope: every message on every device, history forever and searchable, Seen and typing.
- Numbers: 5 devices per one-to-one message, about 5 million deliveries a second.
- Catching up: a numbered log per person, a cursor per device.
- Seen: one read marker per person per chat, from any device.
- Typing: passed on to open chats, never stored.
- Search: an index per person, fed off a queue.