A photo feed end to end: the numbers, who fills each user's timeline and when, how ranking fits in a latency budget, what photos cost to store and serve, why paging through a moving list needs cursors, and what happens when the most-followed account posts. Tap any for a plain-language card.
A feed shows posts from hundreds of people you follow, newest and best first. Building that on every open is the whole problem.
The standard answer is a precomputed timeline per user: a short list of post ids (not whole posts) kept in a fast store such as Redis, so a read is one lookup plus fetching post details for the top page. The list is small because it holds ids and only the latest few hundred. The question for the rest of the lesson is who fills those lists, and when.
500 million daily users posting twice a day make about 11,600 posts a second; opening the feed 10 times a day each is 58,000 reads a second. Holding 500 post ids of 16 bytes for each user takes 4 TB.
Posts published per second11.6K
Feed reads per second57.9K
Reads per post5
Memory for every user's timeline4.0 TB
500 million users make 11.6K posts and 57.9K feed reads a second, 5 reads for each post. A precomputed timeline of 500 ids at 16 bytes for each user needs 4.0 TB: sharded in memory, that is affordable, and it turns a read into a lookup.
Arithmetic with illustrative inputs. Real products have far more read traffic from scrolling and refresh than from opens.
Do the work at write time or at read time?
When someone posts, do you copy it into every follower's timeline now, or let each follower's read go and fetch it later?
Followers are wildly uneven, so real systems use a hybrid: push for ordinary accounts (a few hundred followers) and pull for celebrities (millions), merging the celebrity posts into the pushed timeline at read time. This is the classic trade. Try your own numbers; the cheapest column depends on the follower distribution.
With 500 M users, 150 followers on average and 20 celebrity accounts followed per user: push costs 197,000 writes a second, pull costs 9.8 million lookups a second, and the hybrid costs 174,000 writes plus 1.2 million lookups.
Push to followers' timelines (fan-out on write)
197K writes + 57.9K reads per second
Build at read time (fan-out on read)
0 writes + 9.84M reads per second
Hybrid: push, but pull celebrities
174K writes + 1.22M reads per second
Average followers per account170
Celebrity accounts followed by each user20.0
Biggest burst from one post: push / hybrid200K / 150 writes
At these numbers push needs 197K writes a second and a single celebrity post is a burst of 200K writes; pull needs 9.84M lookups a second; the hybrid needs 174K writes plus 1.22M lookups, and its biggest burst is only 150. The hybrid trades a little read work for removing the celebrity spike.
Arithmetic for 500 million users opening the feed 10 times a day. A "write" is one timeline insert; a "lookup" is one fetch of an account's recent posts. The bars add the two, which treats them as equal cost: weigh them for your own stores.
Newest first, or best first?
Ranking by “what you will care about” beats ranking by time. But a model has to score hundreds of candidates before the page appears.
Every stage spends part of a fixed budget: users notice a feed that takes more than a few hundred milliseconds. Scoring cost grows with candidates × model cost ÷ parallelism, so the lever is usually to score fewer items with a cheap model first and a costly model second. Features are precomputed and fetched from a feature store, not calculated on the fly. Set the stages and see what fits.
Retrieval 15 ms, scoring 500 candidates at 200 µs each across 8 cores 12.5 ms, hydration 25 ms: the page is ready in about 53 ms. Score 5,000 candidates and scoring alone takes 125 ms.
Retrieve
15 ms
Score
12.5 ms
Hydrate
25 ms
Total
53 ms (budget 200)
Server time to build one page53 ms
Share spent scoring24%
Retrieving, scoring 500 candidates at 200 µs on 8 workers (12.5 ms) and hydrating take 53 ms in total against a 200 ms server budget.
Arithmetic: scoring time = candidates × cost ÷ workers. The 200 ms server budget is an illustrative target that leaves room for network and rendering.
Photos are the heavy part
The post is a few hundred bytes. The photo is two megabytes, and every phone and screen wants a different size.
Two numbers dominate: storage (every rendition is stored alongside the original, so storage is a multiple of the upload size, forever) and egress (views × bytes per view, mostly served from the CDN cache). The CDN hit ratio decides how much reaches your origin. Smaller formats cut both. Set yours.
100 million photos a day at 2 MB with four renditions at 30% of the original's size each is 440 TB of new storage a day, about 800 PB in five years. At 50 views each and 150 KB per view, 750 TB a day leave the CDN; a 95% hit ratio leaves 38 TB at the origin.
New storage per day440 TB
Five years of storage803 PB
Served to users per day750 TB
Reaching your origin per day38 TB
100 million 2 MB photos a day with 4 renditions need 440 TB of new storage a day (803 PB over five years). Views send 750 TB a day to users; a 95% CDN hit ratio leaves 38 TB for the origin.
Arithmetic: storage = photos × original × (1 + renditions × ratio); egress = photos × views × bytes per view. Ignores videos, replication and deletions.
The list moves while you scroll
You read page 1, scroll, and page 2 starts with the post you just saw. Or skips one. Why?
Cursors also scale better, since the database seeks directly to the cursor with an instead of counting past thousands of rows. The cost is that you cannot jump to page 37; for infinite scroll that does not matter. Opaque cursors (an encoded id and timestamp) also let you change the internals later. Raise the arrival rate and the time spent reading.
With 3 new posts a minute and 20 seconds on a page, offset paging repeats 1 post on average and 64% of page-2 loads are shifted. Cursor paging repeats none.
Offset: repeated posts per page load
1.00
Offset: skipped posts per page load
0.00
Cursor: repeated or skipped
0
Page loads that are shifted (offset)64%
Page loads that are shifted (cursor)0%
While you read for 20 s with 3 new posts a minute, offset paging shifts 64% of page-2 loads, repeating 1.0 posts on average. A cursor anchored on the last post you saw never repeats or skips.
Seeded simulation: arrivals and deletions during the reading time are Poisson; the shift is arrivals minus deletions (capped at the page size).
Pick the approach
Six situations, four approaches.
Each situation has one approach that fits best. Each answer is worth 20 XP.
Ask: who has how many followers, how big is the read load, and is the list moving?
Question 1 / 6
Most accounts have a couple of hundred followers and feed reads far outnumber posts.
Tip: press 1 to 4 to answer, Enter for the next one.
Who lives by this
Feeds in production.
Published write-ups of timeline and photo systems.
Timelines at scaleTwitter
precomputed Redis timelines
Twitter engineers described keeping each user's home timeline precomputed in memory, filled by fan-out on write, and handling accounts with huge follower counts by merging their tweets in at read time rather than pushing them.
Ranking the feedFacebook EdgeRank
affinity, weight, time decay
Facebook's early News Feed ranking, publicly called EdgeRank, scored each story by how close you were to its author, the weight of the interaction type, and how old it was, an early example of ranking by engagement instead of time.
Small mappings in RedisInstagram
key-value pairs in Redis
Instagram's engineering blog described storing hundreds of millions of media-id to user-id mappings in Redis, using hashes to cut memory use, an example of choosing compact in-memory structures for hot lookups.
A photo store for many small filesFacebook Haystack
object store for photos
Facebook's Haystack paper described a photo store that packs many photos into large files and keeps their index in memory, because a file-per-photo design made metadata lookups the bottleneck.
Interview angle
What interviewers actually ask.
Six questions, each worth 20 XP. Strong answers explain the fan-out trade and the celebrity problem.
State read/write ratio, then push/pull/hybrid, then the celebrity case.
Question 1 / 6
Why precompute a timeline per user?
Tip: press 1 to 3 to answer, Enter for the next one.
Break it
An account with 100 million followers posts. Every follower expects it in their feed. The fan-out service has other work to do too.
Pulling instead gives the celebrity a trivial write (one record) and moves the cost to readers, where a makes it cheap: that one post is fetched once and served to millions. The hybrid also keeps a separate, lower-priority path for big accounts so they cannot starve everyone else, and caps the number of celebrity accounts any one feed has to merge. Compare the two.
100 million followers, 200,000 writes a second of capacity and 150,000 already in use: pushing takes about 33 minutes and reaches only 3% of followers in the first minute. As a pulled celebrity post the write is one record.
Spare fan-out capacity50K/s
Time for everyone to see it33 min
Followers reached in the first minute3.0%
Writes caused by the post100M
Pushing one post to 100 million followers with 50K writes a second free takes 33 min; only 3.0% of followers see it in the first minute, and it delays ordinary users' posts in the same queue.
Arithmetic: time = followers ÷ spare capacity. Real fan-out is parallel and batched, but the capacity limit is what matters.