System design sample solution

System design: design a social media news feed

A step-by-step system design answer you could actually give in 60 minutes.

System design interview · Sample 60-minute answer · Not Amazon's actual design · Independent, not affiliated with Amazon

The system design question

Design a feed like Facebook's where millions of users can post text, images and videos and see posts from the people they follow. Like and view counts should update in real time, and the feed should load almost instantly, even for someone who's just cleared their cache.

Agree on the scope (5 minutes)

Say up front what you're covering.

We'll designWe'll skip
Creating posts with text, images and videoRanking with machine learning
Building each person's feedComments and sharing
Likes and view countsAds
Loading the feed fastModeration

Then agree on what "good" means:

  • Fast: the first screen of the feed shows up in under about 200 ms, cold cache or not.
  • Fresh enough: a new post shows up in followers' feeds within a few seconds.
  • Live counts: like and view counts update within a second or two, and they can be a little off for a moment.
  • Handles celebrities: someone with 50 million followers posting doesn't slow anything down.

Rough numbers (5 minutes)

These are assumptions, but reasonable ones: 500 million people use it a day, each opens the feed about 10 times, 100 million posts a day, an average of 200 followers each, and 10 likes per person per day.

~60K
feed loads per second, on average
~1.2K
new posts per second
~230K
feed inserts per second if we push every post
~20 TB
of new media a day
QuestionRough mathWhat it means
How many feed loads?500 million × 10 a day ÷ 86,400 secondsAbout 60K a second, maybe 150K at a peak. Reads are what we optimize
How much work to push each post to followers?100 million posts × 200 followers ÷ 86,400About 230K small writes a second. Big, but fine if each is tiny
How hot can one like counter get?1 million likes in the first minute of a celebrity postAbout 17K writes a second to one number, too many for a single row
How much media?10 million posts with media × about 2 MBAbout 20 TB a day, so it goes in object storage behind a CDN

The overall design (10 minutes)

Post servicesaves the postPost eventsqueueFan-out workersadd to feedsFeed cachepost IDs per userFeed servicemerges and returns
Posts get pushed into followers' feeds ahead of time. Celebrity posts are pulled in when someone reads their feed.
  1. The app uploads any image or video straight to object storage, then creates the post with text and media links. The post goes into the posts database.
  2. Saving the post puts an event on a queue. Fan-out workers look up the author's followers and add the post ID to the top of each follower's feed list in a cache.
  3. When you open the app, the feed service reads your list of post IDs, adds recent posts from any celebrities you follow, and fetches the post details in one batch.
  4. Images and video come from a CDN, so the feed service only sends small JSON and media links.
  5. Likes and views go to a counter service that adds them up in memory and writes totals every second or so. Open feeds get count updates pushed over a live connection.

What the apps need to do

ActionWho does itWhat's sent
Get an upload linkAppMedia type and size. Returns a link to upload straight to storage
Create a postAppText, media IDs and a request ID so retries don't post twice
Get my feedAppA cursor from the last page, and how many posts
Like or unlikeAppPost ID
Record viewsAppA batch of post IDs seen in the last few seconds
Follow or unfollowAppThe other user's ID

What we store and where

DataWhere it goesWhy
PostsKey-value database, split by post IDHuge and simple to look up by ID
Who follows whomDatabase, split by user, stored both waysFan-out needs followers, and the read side needs who you follow
Feed listsIn-memory cache, split by userLast ~500 post IDs per person, rebuilt if lost
MediaObject storage behind a CDNBig files, read from everywhere
Like and view countsKey-value database, plus in-memory countersTotals saved every second or so
Who liked whatDatabase, split by postSo the same person can't like twice

Step 1: Building feeds: push, pull, or both (12 minutes)

There are two basic options. Push means when you post, we add the post ID to every follower's feed right away. Reading is then one quick lookup. Pull means we do nothing on post, and when you open the app we fetch recent posts from everyone you follow and merge them. Reads get slow if you follow hundreds of people.

Push is better for us because reads outnumber posts by about 50 to 1. Feed lists live in a cache split by user ID, a lot like sharding any big dataset. Each list only holds post IDs and timestamps, so 500 IDs is a few KB per person.

Push breaks for celebrities. One post from someone with 50 million followers is 50 million writes, and they'd land seconds or minutes late. So we mix the two. Above some follower count, say 100K, we don't push. When you open your feed, we read your pushed list and also pull recent posts from the handful of celebrities you follow, then merge by time.

Fan-out runs off a queue, so a burst of posts just makes the queue longer for a bit. Workers can also skip people who haven't opened the app in a month. Their feed gets rebuilt by pulling when they come back.

Step 2: Likes and views at celebrity scale (10 minutes)

If every like does 'add one' on a single database row, a viral post means 17K writes a second to one row, and everything waits on a lock. So don't write each like straight through.

Likes go on a queue split by post ID. Counter workers keep a running total in memory per post and write it every second or so. That's basic stream processing: one write a second per post instead of thousands. For the very hottest posts, split the count across several sub-counters and add them up when reading.

We still need to stop someone liking the same post twice, so we save who liked what, keyed by post and user. Saving the same pair twice is harmless, which makes retries safe. That's idempotency.

Views are even more frequent, and nobody needs them exact. The app batches them and sends them every few seconds. Counts on screen can be a second or two behind, which is the kind of consistency trade we agreed to up front.

Getting counts to open screens

Each open app keeps a live connection to a gateway, and tells it which posts are on screen. When a post's total changes, we send the new number to the gateways watching it, at most once a second per post. That keeps a viral post from flooding everyone.

Step 3: Loading fast with an empty cache (8 minutes)

'Cleared their cache' means the phone has nothing saved, so the server has to do all the work in one round trip. The feed service reads your feed list, then fetches all the post details in one batched read, and returns the first 10 or 20 posts. Counts and author names come from their own caches in the same step.

Media is the slow part. Send small thumbnails and low-quality preview images first, and let the app load full images and video from the CDN as you scroll. Videos are stored in a few sizes so phones on bad connections get the small one.

On our side, if your feed list isn't in the cache, maybe because you've been away, we rebuild it by pulling from who you follow. That's slower, maybe 300 ms, but only on the first load. We keep the cache's hit rate high by keeping lists for everyone active in the last few weeks.

Choices you should be able to defend

We choseInstead ofBecauseWe'd reconsider if
Push for most people, pull for celebritiesPush for everyoneCelebrity posts would mean millions of writes eachNobody had a huge following
Counts added up in memory, written every secondOne database write per likeOne hot post would hammer a single rowTraffic was low enough that rows never got hot
Counts can be a second or two behindExact counts at all timesPeople don't notice, and exact would cost a lotCounts drove something like payments
Feed lists hold IDs onlyFull posts copied into every feedEdits and deletes only touch one place, and lists stay tinyFetching post details became the slow step

What could go wrong (5 minutes)

What happensWhat we do about it
The feed cache loses a machineThose users get feeds rebuilt by pulling, a bit slower, until the cache fills back up
Fan-out falls behindPosts show up late in feeds, but nothing's lost. Add workers
A counter worker crashesRestart from the last saved total and replay the queue from there
A post goes viralIts count is split across sub-counters, and screen updates stay at once a second
The CDN is slow in one regionSend other image sizes or fall back to a second CDN

Follow-up questions (5 minutes)

How would you add ranking instead of newest first?

Pull a few hundred candidate posts from the feed list, score them with a model using things like how often you interact with the author, and sort. The feed list stays the same.

What happens when someone deletes a post?

Mark it deleted in the posts database. Feed lists still hold the ID, but the feed service skips deleted posts when it fetches details.

What if someone follows a new person?

Pull that person's last few posts into your feed list right away, so it doesn't feel empty.

How the 60 minutes add up

MinutesWhat you're doing
0–5Agree on what you're building
5–10Rough numbers
10–20Draw the overall design
20–32Building feeds: push, pull, or both
32–42Likes and views at celebrity scale
42–50Loading fast with an empty cache
50–55What could go wrong
55–60Follow-up questions

Key concepts used here

Further reading

We wrote this sample answer ourselves.

Practice Loop is independent and isn't affiliated with or endorsed by Amazon.