Section 7: Fifty Milliseconds, Twenty Clean Posts - Deep Dive (Candidate-Driven)
Executive Summary: The interviewer hands you the wheel, and you take it to the read path. Ranking scores about 500 candidates in a 50 ms budget, with a chronological fallback. Pagination ranks once per open and pages over a 1.6 KB session snapshot, so scrolling never duplicates or skips. Hydration turns IDs into posts from a 99%-hit cache, and a read-time visibility filter drops deleted, blocked and unfollowed posts. Read-your-own-writes gives Dev his own post instantly while everyone else waits up to 5 s. Fan-out and the celebrity problem get their own dive in Section 8.
You: "The biggest subsystem is fan-out and the celebrity problem. I'd like to give that its own dive right after this one. First, the read path, because that's where 175K opens a second land and where the 200 ms p99 lives."
Section 6 walked Maya's 9:00:04 open in four steps. Each step hides a problem.
| Wall | The question | What users see if it's wrong |
|---|---|---|
| Ranking | Can we score ~500 candidates in 50 ms? | A slow first page |
| Pagination | How does page 2 follow a ranked page 1? | The same post twice, or posts that vanish |
| Hydration and visibility | How do IDs become posts Maya is allowed to see? | A deleted or blocked post on screen |
| Read-your-own-writes | Does Dev see his post the moment he shares it? | "My post disappeared", then a duplicate |
The budget from Section 2 frames all four: candidates ~15 ms, ranking 50 ms, hydration ~30 ms, the rest headroom, inside a 200 ms p99.
Wall 1: Ranking 500 Candidates in 50 Milliseconds
Start with the candidates. Maya's feed cache holds 480 pushed IDs, Dev's 9:00:00 hike photo among them. One batched multi-get reads her 20 celebrity timelines. Keep celebrity posts newer than the oldest entry in her feed cache, but never older than 48 hours (the merge window), dedupe by post ID, and take the newest ~500 of the union. For Maya that adds about 20, @luna_sings's 8:58 post among them. That's the ~15 ms.
This is the whole first-page open, from candidates to response:
Ranking itself is three steps:
- Feature fetch. One batched read from the feature store for all 500 candidates: Maya's affinity with each author, recency (read straight from the post ID), engagement velocity (how fast the post is collecting likes), and media type. Pipelines compute these ahead of time.
- Score. 175K opens × 500 candidates is ~87.5M scores a second at peak, the biggest compute line in the system. So it's a light model over precomputed features.
- Re-rank for diversity. No more than 2 consecutive posts from one author, and posts in Maya's served set move down:
served:{user_id}, the last 200 post IDs actually returned to her (1.6 KB, TTL 24 h, ~0.8 TB for 500M daily actives).
Dev's photo comes out at position 1: strong affinity, 4 seconds old. @luna_sings's post lands at position 2.
If the Ranking Service misses its deadline, the Feed Service sorts the same 500 candidates by post ID, which embeds time. Maya gets a chronological feed, and a degraded feed still counts as up.
Interviewer: "Why not score posts at fan-out time and store each feed already ranked? Then reads are free."
You: "Two reasons. Scores go stale. At 8:58 @luna_sings's post has a handful of likes, and by 9:00 it has hundreds of thousands, and engagement velocity is one of the strongest features. And some inputs only exist at read time: what Maya saw an hour ago, when she's opening the app. Celebrity posts aren't fanned out at all, so they'd need read-time scoring anyway. If ranking's p99 busts 50 ms, I first cut candidates to about 200, then precompute scores offline for the heaviest users."
Key Insight: Rank once per open, not once per page. That one rule makes ranking affordable and makes Wall 2 solvable.
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson