Design WhatsApp
How to Solve Design WhatsApp
What is the Design WhatsApp Problem?
The Design WhatsApp problem asks us to design a message app system and client that supports a number of requirements. Due to the nature of the problem, it casts a wide scope. It's important to not get lost in all the features and spread yourself too thin when answering this problem. Because the question is so broad, pay extra attention to the requirements laid out by the interviewer. A key area to focus on will ensuring no messages are lost.
An Example of the Design WhatsApp Problem
Design a message app system and client (e.g., WhatsApp) supporting the following requirements:
- 1:1 messaging
- Broadcasting (a few people can write; others can read)
- Group messaging (everyone can write, but there are owners/moderators)
- Msg send/receive confirmation (acknowledge) to make sure no message lost between clients
- Image/media/file sharing
How to Solve the Design WhatsApp Problem
Aside from basic topics such as the messaging server, there are many topics we can cover. To save time during a system design interview, let’s first focus on the functional requirements. This exercise will also help us clarify the problem statement. WhatsApp is a broad problem, and each interviewer will have different goals and priorities in mind, so it is even more important here than in other questions to first clarify what we are solving for.
User-facing features (close to the FRs in this case) to clarify include:
- Online status
- Offline messaging, and storing the message
- Push notifications
- Location sharing
- Registration
- Invite links
- SMS/email confirm
- Group management
- Bio lines
- “Is typing …”
- Statuses
- Profile pictures
- Encryption / security / privacy
Note:
When it comes to storing the messages, even though for 1:1 communication it may be desirable to create a solution in which all messages live on users’ devices, it is hard to scale to channels and groups. So, unless the problem statement is specifically about designing an app like "Signal" and not WhatsApp, let’s assume our servers do store all the messages.
- Lost Messages: How do we handle lost messages? Is this sometimes acceptable or never okay?
- We would hope to not lose any messages. The way we display when a message is lost is the usage of ticks. One tick means the message has been sent from the user to the servers, a second tick means it’s been delivered to the recipient, and a change in color of the ticks to blue signifies it has been read. In the event that there is an outage or high load on the system, we can display a loading symbol on the message that the user is attempting to send. If this message fails to reach the server, we display a cross symbol and provide the user with an option to retry.
- Message order: Should each user see the messages in the same order?
- Ideally, the order should be preserved. But it’s not the end of the world if in a busy group multiple users’ feeds do not 100% agree with each other about which message came first if they were sent around the same time. In 1:1 conversations, of course, we expect the order of messages to be preserved (although there might be some wiggle room for multiple devices, see below).
- History: Hot/Cold. Hot when a particular device was offline for a short while; Cold (long) when adding a new device, or powering on a device that was offline for ~years.
- If the history is stored on our servers, delivering most recent conversations to a new user device should not be a problem. If the user wants to pull earlier messages, they can scroll up and it’s acceptable to show a loading symbol and a small wait of a few seconds to pull the next batch of messages (30 or so).
- Multiple devices: What if I have WhatsApp open on my phone, laptop (browser), and tablet. How do the messages appear everywhere?
- Synchronizing multiple devices later on is a separate challenge, but it boils down to sending my own messages to “myself” on other devices.
For non-functional requirements, it would be useful to mention scalability (can add machines to serve more users / more messages), durability, and fault tolerance (to keep delivering and to not lose messages even if our service is partially down).
High-level architecture
Here’s an overview of our high-level architecture. It’s useful to keep in mind that, although this represents a hierarchy for implementation, it does not represent an order of priority for discussion in a real interview.
Most interviewers would want to get down to the critical path, the “life of a message,” i.e., how the messages travel through the system to ultimately get delivered from user A to user B. This is the part of the conversation where message routing and message queues come into play, both of which we will cover below.
With this said, the high-level architecture — which most interviewers would only want to spend a few minutes talking about — would include approximately the following components:
User Management
- Handle user registration and authentication.
- Maintain user profiles, including contact lists and group memberships.
Group Management Service
- Admin controls.
- Remove users.
- Add users.
- Change group name/profile picture.
- Provide moderator privileges.
Messaging Server
- Responsible for handling message routing and delivery.
- Supports both group messaging and 1:1 messaging.
- Manages message queues for offline users and ensures message delivery upon their availability.
Connected Users Registry Service (message routing)
- So that Messaging Servers could know if other users — the recipients of messages — are online at a given time.
Message Storage
- Stores messages temporarily for offline users.
- Provides message history for users to retrieve past conversations.
Acknowledgment Mechanism
- Implements a confirmation mechanism to ensure message delivery and receipt acknowledgment.
- The server tracks acknowledgments from clients and resends messages if not acknowledged within a certain timeframe.
Image/File Sharing
- Implements functionality to upload, store, and retrieve images and files.
- Assigns unique identifiers to each uploaded file for efficient referencing in messages.
Notification Service
- Sends push notifications to mobile devices and real-time updates to web-based clients.
- Notifies users about new messages, message delivery, and other relevant activities.
Client Applications
- Provide user interfaces for sending/receiving messages, managing contacts, and joining groups.
- Allow users to send text messages, images, and files.
- Implement real-time updates for incoming messages and notifications.
- Display message delivery status per communication with the Acknowledgements service.
Overall Flow
Here's how the overall flow of the system could look:
- User registration and authentication are handled by the User Management component. Users create accounts, provide necessary details, and authenticate themselves to access the messaging system.
- Once authenticated, users can send/receive messages using the client application. They can choose between 1:1 messaging or group messaging. For 1:1 messaging, users select a recipient from their contact list. For group messaging, users join specific group servers and send messages to all group members.
- When a user sends a message, the client application communicates with the Messaging Server. The server receives the message, stores it temporarily for offline users (in a queue), and routes it to the intended recipients or group members.
- The server tracks message acknowledgments from clients. Upon receiving an acknowledgment, the server marks the message as delivered. If an acknowledgment is not received within a specific timeframe, the server resends the message to ensure delivery.
- The Message Storage component stores messages temporarily for offline users and maintains message history for users to retrieve past conversations.
- Image/File sharing is supported by the system. Users can upload images/files, which are assigned unique identifiers. These identifiers are then included in messages, allowing recipients to download and view the shared content.
- The Notification Service sends push notifications to mobile devices and real-time updates to web-based clients. Users receive notifications about new messages, message delivery, and other relevant activities.
- Client applications continuously check for incoming messages and display real-time updates. When a new message arrives, the client application receives it from the server and displays it to the user. The application also shows the delivery status of sent messages, indicating whether they are sent, delivered, or read.
Notification system:
We want a scalable and reliable notification system that can handle delivery of notifications to millions of users. In practice, the vast majority of push notifications will be sent to Apple and Android devices, and both of these ecosystems have mature APIs. On our side, we just need to scale the fanout part, so that if a user is not presently online and in the app, a message to them does, by default, result in a push notification sent their way. Handling this correctly intersects a lot with the ultimate message delivery path. If we end up using some kind of a publish-subscribe paradigm, the service that sends out push notifications can be one of the services on the message consuming side, i.e., one of the services that is decoupled from the sender of the message. If this is our design, this particular consumer can be referred to as the Notifications Service, although it does not have to be factored out into its own dedicated service with alternate designs.
Image and file handling:
To handle image and file handling in the message app system, it is important to set certain parameters and implement appropriate storage mechanisms. First, a maximum file size limit should be defined (this limit will be separate for images / videos which have their own limits). For this problem we can assume images will be 5 MB in size — this limit can be considered as the maximum size for images shared within the system. Additionally, it is crucial to define acceptable image formats and implement server-side validation to prevent the sharing of malicious files that could compromise the system's security.
To efficiently store and retrieve images and files, scalable and performant storage mechanisms should be implemented. One recommended approach is to utilize a content delivery network (CDN) or distributed storage solution. Among the available options, Amazon S3 (Simple Storage Service) stands out as a reliable and feature-rich service.
Message Length and Size:
We can define a maximum message length to prevent abuse of the service and ensure efficient storage and transmission. For example, we can set a maximum limit of 4096 characters per message. We can also determine the maximum size of a message by considering the total length of the text, metadata, and attachments (e.g., images).
API Design for Sending Messages:
Post 1:1 message api {"sender": "sender_auth_token","recipient": "recipient_id", "message": "message_content", "client_timestamp": "message_timestamp"}
For group messages: {"sender": "sender_auth_token", “recipient_group”: “group_id”, "message": "message_content", "client_timestamp": "message_timestamp"}
Response: { "messageId": "unique_message_id", "status": "success", "server_timestamp": "message_timestamp"}
Message Routing and Delivery:
First and foremost, we will have more than one Messaging Service in our system, and Messaging Servers will be talking to one another — because, at least in the case of 1:1 messaging when both parties are online, delivering the message directly is the best way to get the job done.
Upon receiving a message from a sender, the Messaging Server determines the recipients. For 1:1 messaging, the server identifies the recipient's client device or devices and establishes direct connections to deliver the message. The message also needs to be stored into a database. Moreover, since the recipient may be offline, the notification service should receive the message too, so that they could be notified.
Real-time Communication:
To enable real-time communication between the server and clients, we can utilize WebSockets between user devices and Messaging Servers. WebSockets provide full-duplex communication channels over a single TCP connection, enabling bidirectional real-time communication between clients and the server.
Message Queues and Publish-Subscribe Mechanisms:
To handle message distribution to multiple recipients and group members, we can implement message queues or publish-subscribe mechanisms. Messages are placed in queues and delivered to recipients when they come online and become available. On the other hand, publish-subscribe mechanisms allow for efficient broadcasting of messages to multiple subscribers.
Data replication, partitioning, and caching:
For data partitioning, we can implement strategies that distribute the message load across different servers or shards based on user identifiers or other relevant factors. This allows for horizontal scalability and enables the system to handle a large volume of messages and users.
Database Design:
Our messaging app system utilizes a relational database to store and manage message data. The database schema is designed to efficiently store message content, metadata, sender/receiver information, and timestamps.