Skip to lesson
‹

Courses / System Design Interview / Chapter 24

Module 3 · Design Real Products · Chapter 24 of 39

Design a Q&A Site

20 sections · ~39 min✓ Fact-checked

Builds on Back-of-the-Envelope Estimates, Databases: Replication, Partitioning and Choosing a Store, Consensus, Leader Election and Coordination, Content Delivery Networks, Distributed Caches, Message Queues, Rate Limiters, Distributed Search and Sharded Counters. Next up: Design Maps and Navigation.

Part 1 · Requirements and Scale

The brief

At 9:40 pm on a weekday, a popular open-source charting library ships version 5.0, and by 10 pm builds are failing in offices and hostels from Bengaluru to Noida. Thousands of developers paste the same error into a search engine and land on one page: question 42, "Build fails after chartkit 5.0 update". Yesterday it had eight views an hour; tonight it has a thousand a second. If every view runs four database queries and adds 1 to a single view-count row, the database stalls and the one page everyone needs times out. This chapter keeps that page fast, its votes honest and its counts cheap.

You are building a Q&A site for programmers: people ask questions, others answer, and the community votes the best answers to the top. The site serves about 100 million page views a day, and most visitors arrive from a web search, read one page and leave without signing in. Question 42 is our running example, from a quiet page to its viral night.

What we are building

Start with what the site must do, then with how well it must do it. Question 42 shows the shape: one asker, a few answerers, a few hundred voters, and a crowd of readers who never post anything.

A Q&A site stores questions, the answers under them and votes on both. A post's score is its upvotes minus its downvotes, and the score decides which answer a reader sees first. Most visitors search for an error message, read the top answer and leave. This is a read-heavy product, and the question page is the product.

The table splits each feature area into what we build today and what waits:

In scopeOut of scope today
AskingPost a question with a title, body and up to 5 tags; edit itBounties, drafts, private team spaces
AnsweringPost answers; the asker accepts oneChat rooms, live sessions
VotingUp or down on questions and answers; change or undo a voteBadges and achievements
FindingQuestion pages, tag listings, searchA personalised home feed
TrustReputation from votes; spam control and moderationAds, job listings

The scope is small on purpose; the difficulty lives in the non-functional requirements, each with a number the design can be held to:

  • Fast pages: a question page loads in under 200 ms for 99% of readers, most of whom are not signed in.
  • Correct votes: one vote per user per post, never counted twice, and voters see their own vote at once.
  • Fresh enough: other readers may see a score that is a minute old, but a new answer should appear within seconds.
  • Durable and available: a posted answer is never lost, and reading keeps working even when posting is degraded.

How much traffic do those promises have to survive? The next page puts numbers on it.

How big it gets

Requirements say what to build; numbers say where the effort goes. Assume 100 million page views a day, about 1 in 10 from signed-in users, 50,000 new questions and 100,000 answers a day, and 1 million votes a day. Most posts are 1 to 3 KB of text. Evenings run about 3 times the average.

Try it first: from those numbers, what peak page-view rate do you design for, how many writes arrive each second, and how much text piles up in ten years?
  • 100 M ÷ 86,400 s ≈ 1,200 page views a second; with a 3× evening peak, design for about 3,500.
  • Votes are about 12 a second and new posts under 2, so writes total about 15 a second: roughly 100 page views for every vote.
  • 150,000 posts × 2 KB ≈ 300 MB a day; × 3,650 days ≈ 1.1 TB, which fits on one large server.

Here is the working in one place:

QuantityWorkingResult
Average page views100 M ÷ 86,400 s≈ 1,200 /s
Peak page views× 3 in the evening≈ 3,500 /s
Votes1 M ÷ 86,400 s≈ 12 /s
New questions and answers150 K ÷ 86,400 s≈ 1.7 /s
Text added per day150 K posts × about 2 KB≈ 300 MB
Text after ten years300 MB × 3,650 days≈ 1.1 TB

Reads outnumber writes about 100 to 1, so every read must be cheap. The read rate itself is modest, which points to caching whole pages rather than to a giant database. Ten years of text fits on one large server; even with votes, edit history and indexes it is a few terabytes, so partitioning, if it comes, is for growth and easier operations, not for today's size.

The danger is concentration. Question 42 on its viral night takes about 1,000 views a second, almost a third of the whole site's peak, on one page. Its page and its view count are where the design must not break.

Part 2 · API, Data and the Big Picture

The API

With the load known, the API decides which calls can be cached and which must reach the database. A short list covers the product; the interesting one is voting.

http
POST /v1/questions                 { title, body, tags[] }  -> 201 { questionId }
GET  /v1/questions/42?sort=votes                           -> 200 { question, answers[] }
GET  /v1/questions/42/my-votes                             -> 200 { votes: { postId: 1 | -1 } }
POST /v1/questions/42/view                                 -> 202   (sent by the page itself)
POST /v1/questions/42/answers     { body }                 -> 201 { answerId }
PUT  /v1/posts/{postId}/vote       { value: 1 | -1 | 0 }    -> 200 { myVote }
POST /v1/questions/42/accept      { answerId }             -> 200
GET  /v1/tags/{tag}/questions?sort=newest&cursor=c9         -> 200 { questions[], nextCursor }
GET  /v1/search?q=chartkit+5.0+build+fails&cursor=c9        -> 200 { results[], nextCursor }

Anonymous readers need no session; every write except the view ping needs a signed-in user.

Voting is a PUT that sets your vote, not a POST that adds one. A double tap that fires the request twice, or a phone retrying after a timeout, repeats the same request with the same result: your vote is +1. Undoing a vote is the same call with value 0. With a POST /upvote that adds a vote on every call, each retry would count again unless the server caught it.

my-votes is the small personal part of a page: which posts this user has voted on. Keeping it apart from the shared question is what lets the shared part be cached for everyone. The view ping exists for the same reason: a page served from a cache never reaches our servers, so the page reports its own view.

Notice that the vote call names only the post, not its question. That looks harmless now; the page on growing the database shows when it stops being harmless.

The data model

The calls fix the questions the store must answer. The entities are few and the relationships simple, so a relational database fits well: questions have answers, posts have votes, questions have tags.

usersid (pk)namereputationcreated_at
questionsid (pk)author_idtitlebodyanswer_countaccepted_answer_idcreated_at
answersid (pk)question_idauthor_idbodycreated_at
votesquestion_id + post_id + user_id (pk)value (+1 or -1)created_at
post_scoresquestion_id + post_id (pk)score
view_countsquestion_id + shard (pk)views
question_tagstag + question_id (pk)created_atscore

Five details carry the design:

  • The votes key enforces one vote per user per post. Questions and answers share one id space, so post_id can point at either, and a second row for the same post and user is rejected by the database itself.
  • Scores are running totals, not sums of vote rows. Adding up vote rows on every page build would be far too slow, so post_scores keeps one row per post, changed in the same transaction as the vote.
  • Views have their own table. Almost every question needs one row (shard 0); the shard column lets a hot question spread over more rows if batching is not enough.
  • question_tags has one row per tag of a question, indexed by tag and date, so "newest questions in chartkit" is one index range read.
  • question_id is in every child row, so a question, its answers, votes and counters can all live on the same shard later.

Edits append a row to a post_revisions table before updating the current body, so edit history and rolling back vandalism are simple reads.

The big picture

Now put the boxes together. Signed-out readers, about 90% of views, get the page from a CDN edge that keeps it for up to a minute. Signed-in readers and every CDN miss reach the web servers, which check a page cache of rendered questions; on a miss they read the question from its database shard, build the page and store it. A vote commits the vote row and the new score in one transaction, then deletes the page-cache copy.

Predict before you watch: question 42 sits at the CDN edge for up to 60 seconds. A signed-in reader upvotes the fix. When does the voter see their vote, and when do signed-out readers see the new score?
  • The voter at once: the reply and the personal layer carry it.
  • Signed-out readers within a minute, when the edge copy expires and one request rebuilds the page.
Animated sceneA vote meets a cached page0:26

Watch for the two copies of question 42: one at the CDN edge, one in the page cache

Read it as steps

Question 42 is cached at the CDN edge and in the page cache. A vote changes one copy at once and the other within a minute.

The vote changed two things at different speeds, on purpose. The person who cares most, the voter, saw it immediately; the crowd saw it within a minute, and in exchange the crowd cost our servers about one page build a minute instead of a thousand reads a second.

Around the edges

After each commit, posts and votes also go onto a queue as events. Separate workers update reputation, the search index and spam checks from it, so none of that slows down posting.

Part 3 · Deep Dives

Caching question pages

Core deep dive

This is the hardest part to get right: caching whole pages is what lets a modest set of servers answer 100 million page views a day, and every freshness promise depends on how the caches are set up.

Think of a newspaper. It prints one edition for every reader and does not print a copy per subscriber; the address label is stuck on afterwards. A question page works the same way: nearly every reader of question 42 sees exactly the same page, so cache the whole rendered page, keyed by question id and sort order.

For signed-out readers, let the CDN keep the page with Cache-Control: public, s-maxage=60, max-age=0, as in Content Delivery Networks: edges keep it for 60 seconds, while browsers check every time and get a cheap answer from the nearby edge. The edge skips its copy for requests that carry a session cookie. Signed-in users are about 10% of views, and they are the ones who post, vote and edit, so they need fresh pages.

The numbers show why this matters. Question 42 at 1,000 views a second sends about 900 a second to the edges. Each edge location fetches the page at most once a minute, and an origin shield, a middle cache layer, folds those fetches into about one a minute at our servers.

Signed-in users still share the cached page. Do not cache a page per user: personal extras, such as their own votes and an edit button on their own posts, come from the small my-votes call, and the browser combines the two. A per-user cache would hold ten copies of question 42 for ten readers and hit almost never.

The page cache need not hold every question. About 2 million questions are viewed in a day, and at about 50 KB a page that is 100 GB, a few cache servers, with least-recently-used eviction keeping the busy pages. A cached page is only useful if it is fresh enough, so how long should each copy live, and what deletes it?

Keeping cached pages fresh

Two caches hold question 42, and they need different rules because they serve different readers. The table sets one rule per layer:

LayerServesFreshness rule
CDN edgeSigned-out readers, about 90% of viewsKept 60 s; new answers, edits and removals purge the URL; votes wait for the TTL
Page cacheSigned-in readers and CDN missesKept up to a day; every change, votes included, deletes the entry
Personal layerThe signed-in user onlyNever cached

Short TTLs belong at the edge; the page cache keeps a page until it changes. Why not a 60-second TTL in the page cache too? Most questions are read less than once a minute, so their copies would expire between readers and nearly every view would miss.

Kept for a day and deleted only on change, a page misses on its first view of the day and after each change. That is at most 2 million first views plus about 1.2 million changes (1 million votes, 150,000 posts and some edits), roughly 3 million builds out of 100 million views. The hit ratio is about 97%, and at a 3× evening peak that means about 110 builds a second, inside a budget of 175 a second, which is 5% of 3,500. Each build is a few queries on one shard.

Two traps remain. A rebuild right after a vote must read from the primary database, not a replica: a replica a second behind would put the old score back in the cache for a day, the stale refill described in Distributed Caches. And when question 42's entry is deleted while hundreds of signed-in readers want it, mark it stale instead: one request rebuilds while the others get the old copy for a moment (request coalescing).

A purge at the CDN reaches every edge in seconds on most networks, so a new answer shows within seconds, and within a minute at worst, when the TTL runs out.

Recording a vote exactly once

Caching handles the readers; now the writers. A vote is rare but must be exact. Each vote does three things: record who voted, change the score, and tell other systems, and the order matters.

What happens on PUT /posts/87/vote { value: 1 }
  1. 1Read the old votethis user's current vote on answer 87: none, +1 or −1
  2. 2Write the new voteinsert or update the votes row; the primary key stops duplicates
  3. 3Work out the changenew value minus old: none to +1 is +1, +1 to −1 is −2, a repeat is 0
  4. 4Update the scoreadd the change to the post's one score row, in the same transaction
  5. 5Publish an eventreputation, search and fraud checks update from the queue

The dangerous moment is a double tap that sends the same vote to two web servers at once. Both read the old vote before either has written, so both believe the change is +1.

Animated sceneOne vote arrives twice0:19

Watch for the primary key picking one winner when one vote arrives twice

Read it as steps

A double tap sends the same upvote to two servers at once. Watch which part of the system stops it counting twice.

Correctness came from the database, not from careful servers. Locking the old vote in step 1 cannot help, because when there is no vote yet there is no row to lock; the primary key on (question, post, user) is what catches the race. The vote row and the score row share question 42's shard, so steps 1 to 4 run as one local transaction, and the losing copy costs only a retry that adds nothing.

A vote that must be exact gets a transaction. A view needs something else entirely, as the next page shows.

Counting views

Votes and views are both counters, so why treat them differently? Because they sit on opposite sides of the limit of a single row.

Every update to one row waits for the lock held by the update before it, so one row caps how fast one number can change: about 1,000 updates a second when each commit waits for a local disk, and about 200 when it waits for a replica in another zone, as Sharded Counters shows. Votes stay far below that: 12 a second site-wide, and perhaps 50 a second on question 42 at its worst. One score row is plenty.

Views are the hot counter. Question 42 takes about 1,000 view pings a second, right at the cap of one row. The two standard fixes compare like this for that one question:

One row, +1 per ping8 sharded rowsBatched on each web server
Writes a second for question 42About 1,000, on one rowAbout 125 per rowAbout 8 in total
Count lagNoneNoneUp to 5 seconds
Lost in a crashNothingNothingUp to 5 seconds of one server's views
Writes a second for question 42

One row, +1 per pingAbout 1,000, on one row

8 sharded rowsAbout 125 per row

Batched on each web serverAbout 8 in total

Count lag

One row, +1 per pingNone

8 sharded rowsNone

Batched on each web serverUp to 5 seconds

Lost in a crash

One row, +1 per pingNothing

8 sharded rowsNothing

Batched on each web serverUp to 5 seconds of one server's views

Batching wins for views. Each web server keeps a small map of question id to count and every 5 seconds writes one views = views + 437 per question. With 40 web servers that is about 8 writes a second for question 42 however viral it gets, and views tolerate both the lag and the rare loss. Shard the row only where batching is impossible, for example if pings land on short-lived functions with no memory between requests, or if every view must be durable.

One more rule keeps the count honest: count a visitor once per question every 15 minutes. A small cache key per visitor and question, set only if absent, filters out refreshes and simple bots before a ping reaches the batch.

Answer order

With votes and views settled, the page must decide which answer comes first. The default is simple: the accepted answer first, then by score, newest first among ties.

Question 42 shows the flaw. Its accepted answer, written for chartkit 4 three years ago, has 900 votes and is now wrong. A new answer that fixes the 5.0 build has 40 votes after one night. Sorted by score, the wrong answer stays on top for months, because old answers had years to collect votes. The site offers a few orders:

SortRuleHelps with
ScoreUpvotes minus downvotesThe default; stable and easy to explain
NewestMost recent firstFast-moving topics such as library versions
TrendingEach vote's weight halves every 30 daysLets the 5.0 fix climb past the old favourite

Trending is the useful default for pages like question 42: the old answer's 900 votes, spread over three years, now weigh only about 50, while the fix's 40 fresh votes weigh 40 and keep growing, so it passes within days. Some sites also stop pinning the accepted answer when another answer clearly outscores it, because the asker may never come back to change the choice.

Ranking stays cheap. A question usually has a handful of answers and rarely more than a few dozen, all on one shard, so the web server sorts them while building the page. No separate ranking service is needed, and each sort order is simply another cached copy of the page.

Readers do not only arrive at a question directly; they browse tags and search, which the next page covers.

Tag listings and search

Question pages are one way in; tag listings and search are the others, and each needs its own index.

Tag listings. Pages like "newest in chartkit" or "highest voted in android" read from question_tags, indexed by (tag, created_at) and (tag, score); its score is a copy refreshed every few minutes, which is fine for sorting. A question with three tags writes three rows when posted. That small fan-out on write makes every listing one index range read. The first page of a busy tag is cached for 10 to 30 seconds.

Cursors, not page numbers

On the viral night the chartkit tag gets a new question every few seconds. With ?page=5, each new question pushes items down and a reader sees some twice. A cursor such as "created before 22:41:07, id 8812" always continues exactly where the last page ended.

Search. An inverted index, as in Distributed Search, covers titles, bodies, tags and answers, fed from the event queue a few seconds behind the database. Ranking mixes text relevance with signals this product has in plenty: score, accepted answers, views and recency.

The same index powers a valuable extra on question 42's night: dozens of people start to ask the same question. Showing likely duplicates while someone types a title points them to question 42 before they post, which saves answerers and moderators hours. Code needs care when text is split into terms: a search for NullPointerException should match the whole word, and "null pointer" should ideally match it too.

Every one of these paths reads from the database somewhere. How far can one database go before it must be split?

Part 4 · Bottlenecks, Failures and Trade-offs

Growing the database

Grow the database in steps, and let the numbers decide each one:

Step 1: one primary, a few replicas

Posts and votes, about 15 writes a second, go to the primary; views arrive in batches.

Page builds, about 110 a second at peak, read from replicas, except right after a change.

Step 2: read-your-writes

Replicas can lag by a second or more.

For a few seconds after you post or vote, your reads go to the primary, so you always see your own change.

Step 3: partition by question id

A question, its answers, votes and counters live on one shard.

A question page is a one-shard read; a vote is a one-shard transaction.

Step 4: tables for other access paths

"All posts by user 77" and tag listings get their own tables, partitioned by user and by tag.

Kept current from the event queue, a few seconds behind.

At these numbers, one primary with replicas could run the site for years, so do not partition early. Partitioning pays off when the site grows many times over, or when chores such as backups, schema changes, index rebuilds and failover get slow on one big database. When you do, question id is the natural key: almost every request is about one question, and one question's data is small.

Here is the catch from the API page. PUT /v1/posts/{postId}/vote names only the post. Once data is split by question id, the vote service must know the question before it can find the shard. Either put the question id in the URL, which the page already knows, or build every post id with its question's shard number inside, so the id alone routes the request. Either way, the shard checks that the post belongs to that question.

After the split, each request finds its data like this:

RequestServed fromPartition key
Question pagePage cache, then the question's shardquestion_id
Tag listingquestion_tags tabletag
User profileuser_posts tableuser_id
SearchSearch clusterdocuments spread across index shards

What breaks

Walk each failure from the reader's side: what they would notice, and what keeps the site up. Question 42's viral night is a good test for each row:

ProblemEffectResponse
Page cache cluster lostEvery request that misses the CDN needs a build at onceCoalesce rebuilds, cap the rate of page builds, warm the busiest pages first; the CDN keeps serving signed-out readers
A question goes viralAbout 1,000 readers a second and a burst of votes on one pageCDN and page cache serve it; batched view counts; stale-while-rebuild on its cache entry
Primary database failsPosting pauses until a replica is promoted, seconds to a minuteReads continue from caches and replicas; the app keeps the draft and retries
A rebuild reads a lagging replicaThe old score is cached for a dayRebuilds right after a change read from the primary
Search cluster downSearch returns errorsTag pages and outside web search still work; show a friendly fallback
A zone or region failsA zone: nothing visible if every tier spans three zones. A region: posting stops thereThe CDN keeps serving cached pages; promote the database copy in a second region and move traffic by DNS

The pattern is the same in every row: reading degrades last. The CDN, the page cache and the replicas each keep pages flowing while the part behind them recovers, and only posting, the rare action, waits.

Vote retries are missing from the table on purpose: thanks to PUT semantics and the votes primary key, a repeated vote is not a failure at all. The best failure handling is a design where the failure cannot do harm.

Trade-offs and running costs

Each choice so far bought something and cost something. These are the ones worth naming:

  • Stale scores for cheap reads: signed-out readers may see a score a minute old, and in return question 42 costs about one build a minute.
  • Batched views: up to 5 seconds of lag and a rare small loss, in exchange for about 8 writes a second instead of 1,000.
  • Fan-out on write for tags: three index rows per question cost little and make every listing one fast read.
  • Soft delete: keeps evidence and allows undo, but hidden posts must be filtered from every read path and from search.

Serving pages dominates the bill. 100 million page views of about 50 KB is roughly 5 TB a day out of the CDN before compression, about 150 TB a month; at $0.05 to $0.10 per GB of egress (check current prices), compression and long-lived static files matter more than any database choice. All the text ever posted is about 1 TB.

The cheapest trade-off of all is the one the requirements made: deciding that a minute-old score is fine. Every cache in this design leans on that one sentence.

Part 5 · Going further

Spam, abuse and moderation

Optional: how an open site keeps spam, vote fraud and abuse in check once the core works.

An open site that anyone can post to attracts spam within days, and a viral page like question 42 attracts it within minutes, because spam answers there are seen by thousands. No single check stops it, so use layers, cheapest first:

LayerWhat it doesExample rule
Rate limitsSlow down new accountsA new account can ask one question every 20 minutes
Earned privilegesUnlock actions with reputationDownvoting needs 50 reputation; editing others' posts needs more
Automatic checksScore each post as it arrivesLinks to known spam domains, repeated text, posting bursts
Community flagsReaders flag posts into a review queueFive spam flags from trusted readers hide a post until a moderator decides
ModeratorsFinal decisions and appealsDelete, lock or suspend, with every action logged

Vote fraud needs its own check. Extra accounts that upvote their owner, or a group that votes each other up, leave a pattern: many votes between the same few accounts in a short time. A nightly job finds these patterns and reverses the votes, which is easier and fairer than blocking each one as it happens.

Reputation unlocks privileges, so compute it with care. A worker reads vote events from the queue and appends a line to the user's reputation ledger, such as +10 when their answer is upvoted, keyed by the vote's event id so a redelivered event is skipped. The profile shows the ledger's sum, cached on the user row. Reversed votes append opposite entries instead of editing history, so every point can be explained.

Limits belong at the edge

Apply per-user and per-IP limits at the API gateway with a shared counter store, as in Rate Limiters, so spam is turned away before it reaches the posting path.

Part 6 · Interview kit

The 45-minute answer

A 45-minute round leaves about 40 minutes of design once introductions and your own questions are done. Here is how to spend them on a Q&A site.

MinutesWhat you say and drawKey number or decision
0–5Ask, answer, vote, accept, tags, search; pages under 200 ms at p99; one vote per user, never counted twice; badges and chat out.The question page is the product
5–8100 M page views a day ≈ 1,200 a second, about 3,500 at peak; about 15 writes a second; ten years of text ≈ 1.1 TB.Cache whole pages; one database lasts years
8–13Shared page plus my-votes; PUT vote with 1, −1 or 0; a view ping; votes keyed by (question, post, user), score rows, view counts, tags.A PUT sets a vote, so retries are harmless
13–22CDN for signed-out pages → web servers → page cache → posts database; vote transaction; a queue for reputation, search and spam.Reads almost never reach the database
22–37Caching: edge 60 s, page cache until change, personal layer, primary rebuilds, coalescing. Then votes (primary key) and batched views.≈ 97% page-cache hits, about 110 builds a second
37–40Growth (replicas, read-your-writes, partition by question id), failures, trade-offs.A minute-old score is the price of cheap reads

Pick page caching if they ask about latency, signed-out traffic or a viral question. Pick votes and views if they ask about correctness, double votes or hot counters. If they push on growth, go to partitioning by question id and how a vote finds its shard.

Say
"Reads outnumber votes about 100 to 1, so I cache whole pages and keep the personal parts, like your own votes, separate."
Say
"The page cache keeps a page until it changes, about 97% hits; only the CDN uses a 60-second TTL, so scores lag a minute at most."
Say
"Votes are 12 a second, so one score row is enough; a viral question's 1,000 views a second are batched to about 8 writes."
Avoid
"Every page view queries the database." At 3,500 views a second that is wasted work, since almost every reader wants the same page.
Avoid
"Votes need sharded counters." A post gets a few votes a second; it is the view count that changes on every read.

Interview drill

Interviewers change one thing to see whether your design bends or breaks. Try each question before opening the answer.

A bigger library breaks: one question gets 20,000 views a second for an hour. What changes?
  • About 18,000 a second are signed out and served by the CDN; the origin builds the page about once a minute.
  • The 2,000 signed-in readers a second hit the page cache; mark the entry stale on change and rebuild it at most once a second.
  • Batched views still write about 8 times a second; the ping endpoint needs about 20 more web servers, or count views from CDN logs.
  • Votes may reach a few hundred a second on one answer: one score row still copes, near its limit.
Product wants answers ordered per reader: by language, library version and what they have not read. What breaks?
  • The shared page cache: a page ordered for one reader is wrong for the next, so the hit ratio falls toward zero.
  • Cache what is still shared: each answer rendered as a fragment keyed by post id and version.
  • Compute only the order per reader, from per-user signals in a new table, and assemble the page from fragments.
  • Signed-out readers keep the default order, so the CDN still serves 90% of views.
The site must survive losing a whole region, with no posted answer lost. What changes?
  • Reads are the easy half: the CDN keeps serving cached pages, and a second region holds replicas and its own page cache.
  • Writes are few, about 15 a second, so a synchronous copy in the second region is affordable: about 30 ms more between Mumbai and Delhi.
  • On region loss, promote that copy through consensus-based failover, so two primaries never accept writes at once.
Common miss
Caching a page per signed-in user, or giving the page cache a 60-second TTL: either way the hit ratio collapses.
Common miss
Treating votes and views alike: votes need exactness and a transaction; views need throughput and can be seconds late.

Wrap-up

Next: Design Maps and Navigation. The data becomes a road graph, and the hard part moves from caching pages to answering route queries in milliseconds.

Part 7 · Check yourself

Quick check

Q1After you partition by question id across 8 shards, about 7 in 8 votes on answers fail with "post not found", while question pages load fine. What went wrong?

Think it through, then check.

Q2Askers can now offer a bounty: up to 500 of their own reputation points for the best answer within 7 days. What changes?

Think it through, then check.

Q3Should signed-out pages stay at the CDN for 10 seconds or for 5 minutes?

Think it through, then check.

Q4The queue that feeds reputation, search and spam checks stops for an hour. What do users notice, and what happens when it recovers?

Think it through, then check.

Q5A wave of new accounts starts posting spam. Which building block turns them away before they reach the posting path, and where does it sit?

Think it through, then check.

Next chapter · 25 of 39Design Maps and Navigation~40 min · 2 animated scenes