...
Assume we have 1B users registerd, and 100M daily active uses.
Assume each of them post 1 tweet each day and the average size of the tweet is 2M as it may contain photo and videos. 100M * 1 * 2MB = 200TB/day => 200TB * 365 * 5 = 365PB to store all tweets
We need to design a user table, and tweet table, and following relationship table
1.post a new tweet
2.view the timeline
Partition
Since this system has a high througput, so we need to partition the database, and store data across all partitions. Here are two approach to partitioning our database
1.Partition by userId
2.Partition by tweetId
Timeline
The straight forward way to generate timeline for a user is we first query database to find all the people this user follows. Then check all the paritions to retrieve the tweets post by these people. Aggregate, sort, rank and return the top K tweets. The problem with this approach is it's very slow because it has to hit the database frequently.
Here is the optimized solution. We can pre generate the timeline for each user, and store it in a key-value store in the Cache. The key is userId, the value is a list of tweets post by the people that this user follows. So every time if a user request to view the timeline, we can directly read it from the cache.
How to update the timeline?? If a user post a tweet, we can push this to all the people following this user.
But here is a problem with the push mode. If a user is a celebrity with large number of followers, then push mode will affact the performance. In this case, we can just let the user send a pull request to the server to retrive tweet of this celebrity from the database.
Therefore, we can implement a hybrid mode. For people with small number of followers, say 500, we can use push mode if he post a new tweet; otherwise we use pull mode.
Store the data in the in-memory cache is costly, but for a read heavy system, it's very necessary to implement caching. We can store the tweets post from last three days. In most case people will only check the most recent tweets.
In this system, we may sacrifice the complete consistency for availabity. Since we have a huge number of tweets to store, we need to partition the database, and distribute tweets to them. And we have replicate each partition to avoid single point of failure. The propagation of update to all replicas take time, so we may not see the most recent update immediately. But in the end we will see that.
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?