List functional requirements for the system (Ask interviewer if stuck)...
List non-functional requirements for the system...
Estimate the scale of the system you are going to design...
It should support 100 million daily active users (DAU)
Each user sends 20 messages per day on average
So 2 billion messages per day
Average message size is 100 bytes (text only)
Media files average size is 2MB
10% of messages contain media files
QPS:
messages: 10 million users * 20 messages per user / 86400 ~ 2300 messages/sec
media uploads: 10% ~ 230 uploads/sec
Peek QPS:
Assuming peak times 3x:
Peak messages QPS: 6900 messages/sec
Peak media uploads QPS: 690 uploads/sec
Storage:
Message: 10 million users * 20 messages * 1kb message =200 GB/day
Media: 10 million users * 2 uploads * 2MB = 20TB/day
Define what APIs are expected from the system...
Send message: POST /api/messages/send
{
"fromUserId": "12345",
"toUserId": "67890",
"message": "Hello!",
"timestamp": "2024-03-20T12:34:56Z",
"messageType": "text", // Could be "media" for media messages
"mediaUrl": null, // URL to media if messageType is "media"
"readReceiptRequested": true
}
Update the online status:
POST /api/status/update
{
"userId": "12345",
"status": "online", // Could be "offline", "busy", etc.
"lastSeen": "2024-03-20T12:34:56Z"
}
Read message:
GET /api/messages
GET /api/messages?chatSessionId=123&limit=50&offset=0
Response:
{
"messages": [
{
"messageId": "msg1",
"fromUserId": "12345",
"toUserId": "67890",
"chatSessionId": "123",
"message": "Hello, how are you?",
"timestamp": "2024-03-20T12:34:56Z",
"messageType": "text", // Or "media" for media messages
"mediaUrl": null, // URL to media if messageType is "media"
"readReceipt": false // Indicates if the message has been read
},
{
"messageId": "msg2",
"fromUserId": "12345",
"toUserId": "67890",
"chatSessionId": "123",
"message": "Check out this picture!",
"timestamp": "2024-03-20T12:35:00Z",
"messageType": "media",
"mediaUrl": "https://example.com/path/to/image.jpg",
"readReceipt": false
}
// More messages...
]
}
If we use gRPC, the proto buffer should be like:
// The chat service definition.
service ChatService {
// Sends a message to a chat session.
rpc SendMessage(SendMessageRequest) returns (SendMessageResponse);
// Updates a user's online status.
rpc UpdateOnlineStatus(UpdateOnlineStatusRequest) returns (UpdateOnlineStatusResponse);
}
// Request message for SendMessage.
message SendMessageRequest {
string fromUserId = 1;
string toUserId = 2;
string chatSessionId = 3;
string message = 4;
string timestamp = 5;
MessageType messageType = 6;
string mediaUrl = 7;
bool readReceiptRequested = 8;
}
// Response message for SendMessage.
message SendMessageResponse {
string messageId = 1;
bool success = 2;
string errorMessage = 3; // Empty if success is true
}
// Request message for UpdateOnlineStatus.
message UpdateOnlineStatusRequest {
string userId = 1;
UserStatus status = 2;
string lastSeen = 3;
}
// Response message for UpdateOnlineStatus.
message UpdateOnlineStatusResponse {
bool success = 1;
string errorMessage = 2; // Empty if success is true
}
// An enumeration of message types.
enum MessageType {
TEXT = 0;
MEDIA = 1;
}
// An enumeration of user statuses.
enum UserStatus {
ONLINE = 0;
OFFLINE = 1;
BUSY = 2;
}
Defining the system data model early on will clarify how data will flow among different components of the system. Also you could draw an ER diagram using the diagramming tool to enhance your design...
You should identify enough components that are needed to solve the actual problem from end to end. Also remember to draw a block diagram using the diagramming tool to augment your design...
Explain how the request flows from end to end in your high level design. Also you could draw a sequence diagram using the diagramming tool to enhance your explanation...
The Messaging Service interacts with the Message Database to store and retrieve messages.
The Presence Service uses a Redis database to quickly update and fetch user online statuses.
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
Explain any trade offs you have made and why you made certain tech choices...
When a client intends to start a chat, it connects the chat service using one or more network protocols. For a chat service the choice of network protocol is important.
HTTP is client initiated, it is not trival to send messages from the server.
Polling vs Long Polling vs Websocket for Web + MQTT(Message Queuing Telemetry Transport) for mobile:
Try to discuss as many failure scenarios/bottlenecks as possible.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?