Total users: 100M
DAU: 10M
Publish per user per day: 2
Read per user per day: 10
Each user follows 500 other users
publish/write QPS: 2 * 10^7 / 10^5 = 200
read QPS: 1000
storage:
size per tweet = 200 + 1*10^6 * 0.1 = 0.1MB
size per day = 0.1MB * 2 * 10^7 = 2 TB
size per year = 700 TB
size per 10 year = 7 PB
Start with relational DB.
Tables:
Publish a tweet flow:
User Table 1 -> n Tweet table
Read tweets flow:
User Table 1 -> n Tweet table
Fav tweets flow:
User Table 1 -> n Fav table 1 -> Tweet table
Client
Load Balancer: balancing traffic to proxy servers
Proxy servers: API gateway, route request to different services, rate limiting, user authentication, security
Publish service: publish a tweet, update tweet table, potentially upload large media to object storage, notify fanout service internally to push new tweets to followers cache
Read service: read recent tweets from cache first, if read more than cache capacity, query from user table and tweet table
Fav service: save (user_id, tweet_id) into fav table, also serves fav read request, which pull data from fav table, tweet table.
Fanout service: upon notified about new tweet, push new tweet to followers cache
Cache: LRU-evicted, keep recent 1-2 days tweets
DB layer contains tweet table, user table and fav table
Publish flow:
Read flow:
Fav flow: similar to publish flow, but just update fav table. When read, read directly from DB since fav read is a less frequent case.
Fanout service:
Read service and cache:
For large / hot media files:
New tweets, push v.s. pull:
SQL vs No-sql:
Object storage and CDN: instead of start from scratch, can outsource to existing provider, like amazon S3, or CDN providers.
Scalability: each component should be horizontally scaled. Proxy servers and each service is stateless, so can be scaled out easily. For DB, we can provide single leader/write server with read replicas for faster read. And may need to further partition into different servers, partition key can be user_id.
Fanout service will have high traffic, we need to scale it more and use message queue to handle the large amount of async fan out jobs reliably.
Failure/error handling: