WhatsApp system design: one message, from sent to read
Follow one message from DK to Rajat: WebSockets, a session cache, durable storage, and the sent, delivered and read ticks travelling back.
Both online
- DK sends: dinner at 8? It leaves his phone already encrypted, over a WebSocket that stays open.
- The load balancer keeps him on the same chat server every time, and Chat Server A gives the message an ID.
- Before anything else, the Message Service writes it to Cassandra, on three replicas.
- Only once it’s safe does DK get one tick: sent, saved on WhatsApp’s servers.
- Meanwhile, Chat Server A asks Presence: is Rajat online? He is.
- But he’s connected to a different chat server, and Redis knows which one: Chat Server B.
- Server A forwards it to B, which pushes it down Rajat’s open socket, and a banner appears on his phone.
- His phone sends back a delivery receipt, relayed the same way, and DK sees two grey ticks, before Rajat has even opened it.
- Rajat taps the banner and opens the chat.
- Opening it sends a read receipt back along the same path, and DK’s two ticks turn blue.
- Now Rajat replies: okay, coach.
- The same path in reverse: Chat Server B gives it an ID, and Cassandra stores it.
- Once it’s stored, Chat Server B acks, and Rajat gets his one tick: sent.
- Chat Server B asks Redis where DK is: Chat Server A.
- Server A pushes the reply down DK’s socket, through the same load balancer, the other way.
- DK has the chat open, so the reply is delivered and read at once, and Rajat’s tick goes straight to blue.
- Every tick you see is a real event, and WhatsApp’s servers never read a word.
Rajat away
- DK texts Rajat: dinner at 8? But Rajat’s WhatsApp is closed. Keep an eye on where the message waits.
- The load balancer keeps him on the same chat server every time, and Chat Server A gives the message an ID.
- Before anything else, the Message Service writes it to Cassandra, on three replicas.
- Only once it’s safe does DK get one tick: sent, saved on WhatsApp’s servers.
- Meanwhile, Chat Server A asks Presence: is Rajat online? No: last seen at 9:40.
- With no live socket to push to, the message is parked in Rajat’s inbox in Redis.
- The Message Service publishes an undelivered event to Kafka, for the Notification service to pick up.
- Notification asks Apple’s push service to wake Rajat’s phone, and a banner lights up his lock screen.
- The push also wakes WhatsApp in the background, just long enough to open a short socket to Chat Server B.
- Chat Server B drains his inbox from Redis and hands over what waited, so the message is now stored on his phone.
- His phone sends a delivery receipt back through the chat servers, and DK sees two grey ticks, though Rajat hasn’t looked at it.
- Rajat never opens it, so the ticks stay grey: delivered, not read.
Media upload
- DK sends Rajat a photo. Keep an eye on the upload: big files never ride the chat socket, so the photo travels on its own path first.
- The app asks the API gateway, and the Media Service hands back a presigned upload URL.
- The phone encrypts the photo and uploads it straight to blob storage: 2.4 megabytes, stored.
- It gets back a media ID, and that small ID is all that rides the socket.
- DK sends the media ID like any message, encrypted, over his open WebSocket.
- The load balancer keeps him on the same chat server every time, and Chat Server A gives the message an ID.
- Before anything else, the Message Service writes it to Cassandra, on three replicas.
- Only once it’s safe does DK get one tick: sent, saved on WhatsApp’s servers.
- Meanwhile, Chat Server A asks Presence: is Rajat online? He is.
- But he’s connected to a different chat server, and Redis knows which one: Chat Server B.
- Server A forwards it to B, which pushes it down Rajat’s open socket, and a photo banner appears on his phone.
- Rajat’s phone downloads the photo by itself, from the CDN.
- The first copy comes all the way from blob storage, and the CDN keeps it at the edge, so the next download is faster.
- Only now, with the photo on his phone, does it send the delivery receipt, and DK sees two grey ticks.
- Rajat taps the banner and opens the chat.
- Opening it sends a read receipt back along the same path, and DK’s two ticks turn blue.
- Heavy bytes through storage and the CDN, a tiny ID through the chat: that’s how a photo travels.