Back to path
IntermediateLinkly · Project 5 of 12 ~5h· 5 milestones

Replicate the database and split reads from writes

Continues from the last build: Rung 4 left you with a stateless, load-balanced app tier that scales horizontally, but every one of those app instances still funnels every single read and write into the same one database.

Your app tier now scales horizontally behind a load balancer, but scaling the app tier just moved the bottleneck one hop over: at 12,000 QPS with a 100:1 read to write ratio, the single Postgres primary is pegged serving SELECT queries for shortcode redirects, and a single disk failure on that one box would take Linkly completely offline with no standby to fail over to.

database replicationread/write splittingreplication lag analysisfailover planningcapacity estimationconsistency modelsread-after-write handlingincident runbooks

What you'll build

By the end: read traffic is served by a sized pool of replicas behind a router that treats the primary as write-only, replication lag is measured and alarmed on, read-after-write correctness has an explicit design instead of an accident, and a documented failover runbook exists for the day the primary dies.

See how we teach, before you sign up

You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:

adr/0005-read-replicas.mdmarkdown
# ADR 0005: Read Replicas for Linkly's Database Tier

## Status
Proposed

## Context
The single Postgres primary serves both the write path (shortcode creation)
and the read path (redirect lookups) at a measured 100:1 read to write ratio.
At 12,000 QPS blended, the primary is CPU-bound on SELECT queries and is a
single point of failure with no standby.

## Options Considered
- Option A: Vertically scale the single primary (bigger box, no topology change)
- Option B: Add read replicas, route reads to replicas and writes to the primary
- Option C: Move to a distributed database with built-in multi-node reads

## Decision
Adopt Option B. Add read replicas behind an app-tier router. Writes always go
to the primary; reads default to replicas unless a request needs read-after-write
freshness.

## Consequences
- Replicas lag the primary by milliseconds to a few seconds under load.
- The app tier needs read/write routing logic, not just a single connection string.
- The primary remains a single point of failure for writes until the failover
  plan in this rung is exercised; replication alone does not solve availability.
- Replica lag must be measured and alarmed, not assumed to be zero.

Reading this file

  • ## ContextState the numbers that force the decision, not just the pain, so a reviewer can check your math.
  • Adopt Option B. Add read replicas behind an app-tier router.The decision line names the mechanism (routing), not just the noun (replicas).
  • - Replicas lag the primary by milliseconds to a few seconds under load.Naming the cost up front is what makes an ADR honest instead of a sales pitch.
  • - The primary remains a single point of failure for writes until the failoverScoping out what this ADR does NOT solve keeps it from being blamed for a later outage it never claimed to fix.

Fill this in as you make the call; keep old ADRs immutable once accepted.

That's 1 of 7 explained code blocks in this single project.

The build, milestone by milestone

  1. 1

    Size the replica pool with real numbers

    4 guided steps

    Adding replicas because 'that's what scaling means' instead of because the math demands it leads to either an underpowered pool that falls over again in a month, or an overpaid one nobody can justify in a review.

  2. 2

    Decide and document the replication topology

    4 guided steps

    Replication is not free: staleness, extra operational surface, and a routing layer are real costs. An ADR forces you to name the alternative you rejected and why, so the decision survives the next engineer who asks 'why don't we just...'.

  3. 3

    Build the read/write router

    4 guided steps

    Without an explicit router, 'send reads to replicas' becomes ad hoc per-endpoint decisions that inevitably send a write-path SELECT to a lagging replica and serve a 404 for a link that was just created.

  4. 4

    Measure replication lag and alarm on it

    4 guided steps

    Treating replication as instant is the single most common assumption that breaks read-after-write and silently serves stale redirects; you can't defend the freshness window from Milestone 3 without a real lag number behind it.

  5. 5

    Write the primary failover plan

    4 guided steps

    No automated failover plan for the primary means the first outage becomes an improvised, high-pressure decision made by whoever is paged, with no agreed answer for which replica to promote.

What's inside when you start

3 starter files, ready to clone
5 guided milestones
4 full reference solutions
7 code blocks explained line-by-line
5 "is it working?" checks
4 interview questions it prepares you for

You'll walk away with

A capacity calculation naming the read QPS, write QPS, and replica count with headroom
An ADR documenting the replica topology, routing rule, and explicit non-goals
A working read/write router (code or pseudocode) that never reads a fresh write from a lagging replica
A replication lag metric with an alert threshold tied to the router's freshness window
A written primary failover runbook naming the promotion rule and repoint steps

This is portfolio-grade. Build it free.

Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.

Start building