Real-world system design
How Twitter scales, from one server to a billion users
How a timeline grows from thousands of users to hundreds of millions — and why the same feature needs opposite designs for an ordinary user and a celebrity. Based on Twitter's public engineering talks, in AWS terms.
Play it — turn the traffic up yourselfStage 1 of 5
Early days (~50K users)
- Web clientBrowser / web client
- EC2 Auto ScalingEC2 Auto Scaling Group
- RDSAmazon RDS
What breaks
Every time someone opens the app you build their timeline on the spot — querying the tweets of everyone they follow — and the database is buckling under those reads.
Building a timeline at read means, for every open, fetching the recent tweets of all the accounts a user follows and merging them by time. That is a heavy fan-in query, run on every refresh by every user, all hitting the one database. It does not scale: the reads are unbounded and the work is repeated for every viewer.
The fix
Flip it around: when a tweet is posted, fan it out — push its id into each follower's precomputed timeline, held in memory, done by background workers off a queue. Reading a timeline becomes a cheap lookup of a ready-made list instead of a query across everyone the user follows.
Build the timeline when a tweet is written, not when it is read — precompute it once, into a per-user list.
Based on: The Infrastructure Behind Twitter: Scale (Twitter Engineering, 2017)
Stage 2 of 5
Fan-out on write (~5M users)
- Web clientBrowser / web client
- ALBApplication Load Balancer
- EC2 Auto ScalingEC2 Auto Scaling Group
- ElastiCache RedisAmazon ElastiCache for Redis
- SQSAmazon SQS
What breaks
Fan-out on write is cheap for ordinary users, but one celebrity's tweet becomes millions of timeline writes at once — and the timeline store is drowning in them.
A user with a few hundred followers costs a few hundred writes per tweet — nothing. But a celebrity with fifty million followers costs fifty million writes for a single tweet, and there are many celebrities tweeting. The fan-out workers amplify each of their tweets into a storm of writes that saturates the timeline store, even though ordinary users cost almost nothing.
The fix
Go hybrid: keep pushing for the ordinary majority — cheap fan-out — but stop fanning out the handful of huge accounts. Their tweets stay in a store, and at read time you fetch the recent tweets of the celebrities a user follows and merge them into their pushed timeline. Push where fan-out is cheap, pull where it is not.
The same feature needs opposite designs for the median user and the hot key: push most, pull celebrities, merge at read.
Based on: The Infrastructure Behind Twitter: Scale (Twitter Engineering, 2017)
Stage 3 of 5
Hybrid at scale (~50M users)
- Web clientBrowser / web client
- ALBApplication Load Balancer
- EC2 Auto ScalingEC2 Auto Scaling Group
- ElastiCache RedisAmazon ElastiCache for Redis
- DynamoDBAmazon DynamoDB
- SQSAmazon SQS
- RDSAmazon RDS
What breaks
Timelines are handled, but every tweet in the world is still written to one database — and at fifty million users its writes are the wall.
The hybrid timeline scales reads, but there is still one place every tweet is stored, and a single database can only take so many writes however large the machine. At this scale you hit that ceiling — and a global auto-increment id, handed out one at a time, becomes its own bottleneck the moment you try to spread the writes.
The fix
Shard the tweet store across many databases so writes spread out instead of stacking on one. The catch is the id: you cannot ask one server for the next number without recreating the bottleneck, so Twitter built Snowflake — a 64-bit id made from a timestamp, a machine number and a per-machine sequence, generated anywhere, unique everywhere, and still sortable by time.
Past one database's writes you shard the tweets — and sharding needs ids generated anywhere without a central counter (Snowflake).
Based on: Announcing Snowflake — distributed id generation (Twitter Engineering, 2010)
Stage 4 of 5
Global (~200M users)
- Web clientBrowser / web client
- ALBApplication Load Balancer
- EC2 Auto ScalingEC2 Auto Scaling Group
- ElastiCache RedisAmazon ElastiCache for Redis
- DynamoDBAmazon DynamoDB
- AuroraAmazon Aurora
What breaks
One region is serving the whole world, and the app fleet is stretched — a user on another continent waits on a round-trip across the ocean for every refresh.
The data layer scales now, but a single region has a capacity ceiling and a latency problem: everyone outside it pays the round-trip on every timeline load and every post. A global product has to run close to its users.
The fix
Geographic routing sends each user to the closest region, so timelines load and posts land near home and the load splits across regions instead of stacking on one. Each region runs its own app fleet, timelines and tweet shards, replicating where a user in one region follows accounts in another.
At global scale you run the stack in every region and route each user to the nearest one.
Based on: The Infrastructure Behind Twitter: Scale (Twitter Engineering, 2017)
Stage 5 of 5
Planet scale (~350M users)
- Web clientBrowser / web client
- Route 53Amazon Route 53
- ALBApplication Load Balancer
- EC2 Auto ScalingEC2 Auto Scaling Group
- ElastiCache RedisAmazon ElastiCache for Redis
- DynamoDBAmazon DynamoDB
At planetary scale Twitter is a full timeline stack in every region behind geo-routing — pushing for the many, pulling for the famous, and generating ids that never collide across any of it.
Based on: The Infrastructure Behind Twitter: Scale (Twitter Engineering, 2017)
Now try it yourself
Reading is one thing. Turn the traffic up on Twitter's architecture, watch it break, fix it — then build the whole thing from a blank canvas.
Play the scale journey