List functional requirements for the system (Ask the chat bot for hints if stuck.)...
List non-functional requirements for the system...
Estimate the scale of the system you are going to design...
Define what APIs are expected from the system...
POST comments/create
(user_id/authentication will be an encrypted token in the header)
Payload
{
post_id: xxxx,
content: xxxx,
}
GET comments/{post_id}
example response
{
author:xx,
content:xx,
created_timestamp: xxx
}
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...
We will need one database for user information such as user_id, user_name..etc
We will need another database for the post and comments. Les't call it Post DB.
Since we require the system to have relatively low latency, there will be a lot more read then write since most people will be reading than the comments rather then writing them and we don't have complex relationship or need transaction. We can opt for a non-relational database, and since we want to sort the comments by timestamp, we can opt for a wide column database like Hbase so we can easily query comments and sort on the timestamp column.
In terms of scalability, we want to add sharding to the post DB, assuming each post has a lot of comments, we want to shard on the post_id so we can fetch all comments under 1 post easily.
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. If you are unfamiliar with the tool, you can simply describe your design to the chat bot and ask it to generate a starter diagram for you to modify...
Please see high-level design diagram
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...
When a user is reading comments on a post, it reaches the server, the server query all comments under that post through the comment service, the comment service queries the top x number of comments from HBase, sorted on timestamp.
When a user wants to write a comment, it reaches the server and the server add a new row to the Post DB based on the receive payload which includes the comment content, the server creates a timestamp and insert that to the row as well.
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...
How do we distribute the load across different servers? How does each server know which comment to send to which viewers?
Since there are a lot more reads than write, we want to separate out the write and read traffic by adding a real-time messenger service that handles the read. In order to know when a new comment has been posted, we can integrate pub/sub, which is a messaging system that uses a publish/subscribe model. In our case, the comment service create a new comment, it will publish the new comment to a topic, the real-time messenger service subscribes to the topic and receive the message. We can partition the stream into different topic and each real-time messenger server only subscribes to 1 topic. We want to use a layer 7 load balancer which allows us to route traffic based on the request payload, and ensure users reading the same post will be routed to the same real-time messenger service, so that when a real-time messenger server receives a message, it can just distributes it to all users connected to it.
Explain any trade offs you have made and why you made certain tech choices...
Network protocol:
Since we want to see the comments in real time, we want to choose between polling, websocket or server-sent event.
Polling
The polling approach has the client poll for new comments every few seconds, which can work for a system on a smaller scale, but for a large scale system where more comments are coming in every seconds, the clients need to poll more frequently to keep up with the demand, which puts a lot of strain on the server as well as database.
WebSocket
WebSocket is a good real-time option because the client opens a connection to the server and keeps it open, server keeps a connection open and sends over new data without requiring additional requests.when a new comment arrives, the server distributes it to all clients and enable the comment feed to update, it is more efficient than the polling method. However, in our usecase, most users will be reading and not writing comments, so it doesn't make sense to open a websocket connection for each user as the overhead of maintaining such a connection is high.
Server-sent event:
A better approach is to use Server Sent Events (SSE). SSE is a persistent connection just like websockets, but it is unidirectional and goes over HTTP instead of a separate protocol. This means that it is easier to set up and works with existing infrastructure. This means that the server can send data to the client, but the client cannot send data to the server. Why is this better for our use case? The reason lies in the uneven read >> write ratio. Most viewers will never post a comment, but all viewers need to be able to see new comments. The infrequent writes go over HTTPS via a POST request as discussed earlier, while the frequent reads are better served by SSE.
Although SSE makes the most sense for our usecase, it has its own challenge. One of the main challenge is maintaining the connection in environment where connections are routinely balances across multiple servers. This can disrupt the continuous stream of data, requiring careful configuration of the load balancer to support session persistence or "sticky sessions." This ensures that once a client establishes a connection with a server, all subsequent data for that session is routed to the same server.
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?