System requirements


Functional:

  • Users can compose and share tweets.
  • Users can view other users' posts.
  • Users can favorite other users' posts.
  • Users will be shown an automatically curated newsfeed consisting of the latest posts from their friends.
  • Users can follow/unfollow other users.
  • Posts can include images, video, gifs, etc.
  • 280 characters allowed per post.



Non-Functional:

  • Low latency
  • Eventual consistency




Capacity estimation

  • 50M total users
  • 10M DAU
  • 2 tweets / user / day
  • 1kB avg per tweet without media
  • 10MB avg per tweet with media
  • 20% of tweets have media
  • avg 2Mb per tweet


  • 20M total tweets per day
  • 20M / 10^5 = 200 post QPS




API design

  • Upload a post
  • Get latest feed
  • Inspect a user's profile




Database design

Data to store:

  • Users
  • Posts
  • Following relationships


User Database: User data is modified relatively infrequently, but is probably read somewhat often. It is also likely well structured. A relational DB is a good fit for this case. We can use the following schema to store user data:

  • User ID
  • Full Name
  • User Name
  • Bio
  • Created At


Posts are constantly being created, so we want storage solution that can handle alot of writes. Also, only recent posts will be read heavy, while older posts will be read much less often. Let's use a NoSQL Key-Value store to persist the posts long term, keyed by post UUID. We will discuss how to cache them for near term access later.


Friend relationships are often best represented with a NoSQL Graph database like Neo4j. We will use that solution in this design.



High-level design

Incoming posts should be received, persisted to storage, then fanned out to all users following the post's author. The fanned out posts will be stored in a pre-computed news feed in a cache and fetched by the corresponding user whenever they log in or refresh their client app.


We will need:

  • A web server to receive incomming posts and requests
  • A Database to persist posts
  • A Database to store user metadata
  • A fanout service to fanout posts to their recipient users newsfeeds
  • Fanout workers add posts to the cached newsfeeds for each user.
  • A cache to store the newsfeeds






Request flows

A user posts a new tweet:

  1. API server receives the request
  2. API server forwards request to Post server
  3. Post server generates new UUID for post
  4. Post server saves post to Post DB
  5. Post server sends post ID to fanout service
  6. Fanout service sends post IDs to fanout workers.
  7. Fanout workers add the post IDs to the pre-computed newsfeeds for each recipient user.


A user requests their latest newsfeed:

  1. API server recieves the request
  2. API server forwards to Newsfeed Worker
  3. Newsfeed Worker grabs the latest newsfeed for that user from the cache
  4. Newsfeed Worker reads the posts from the Post DB associated with all of the post IDs in the pre-computed newsfeed.
  5. Hydrated newsfeed with post body and media is returned to the user.




Detailed component design

Some areas we can improve:

  • Use an object store to store media separately from the post metadata:
  • Media can be separated from their post by the post server and stored in a separate object store called Media DB. The lookup keys for these large media objects can be stored in their corresponding post's metadata in the Post DB.
  • Use a message queue to separate the Fanout Server from the Fanout Workers:
  • This would allow us to scale the Fanout Worker pool based on the post traffic without affecting the Fanout Server.


Database design:

  • It's acceptable for a few seconds to elapse between a user posting and their followers seeing that post. Therefore, we can use an eventual consistency model in our DB design, where a single Primary is updated with a new post, and all of its Secondarys are asynchronously updated. All reads will be made from the Secondary, unless the author of the post is reading their own post, in which case the Primary will be read.




Trade offs/Tech choices

  • The fanout/precompute-newsfeed design allows our system to perform the work of computing a newsfeed so that users can fetch the newsfeed with minimal latency. However, This does lead to more cache space being occupied with duplicate info and info that may not be read very often in the case of inactive users. The alternative would be to compute the newsfeed on-demand when the user requests it, but the amount of compute and DB hits that this would require increase latency significantly and hinder the user experience.




Failure scenarios/bottlenecks

  • Database failure: if the primary node of the Post database goes down, one of the secondary nodes can be promoted.
  • The system should be replicated in multiple activity zones to avoid total data loss in a disaster scenario.




Future improvements

  • Search feature: allow users to search for user profiles or content based on topic.
  • Trending topics: generate alternitive feeds per user that provide popular posts or posts that are selected by ML to appeal to the given user.
  • Avoid fanning out posts from celebrities because this would lead to many thousands of duplicates being stored in the newsfeed cache. Fetch these posts on demand when the user requests an updated feed.