sehaj/learn
System design/02 From one server to millions

02.02 · concept · 10 min

Split the database; scale up or out

Give the database its own machine, then grow each part either by making its machine bigger or by adding more machines.

The problem: two jobs, one machine

A few months in, Snip has a few thousand users. Once a month an owner downloads a report of every click on every link, and while that query runs, redirects slow from 5 ms to 400 ms. The database and the app are on the same machine, so a heavy query takes CPU, memory and disk bandwidth away from everything else.

The two parts also want different hardware. The app needs CPU and very little disk. The database wants lots of memory (to keep hot data out of the disk) and fast storage. On one machine you can't size either one properly.

Step 1: give the database its own machine

Snip: move the database out

ChangeThe database moves to its own server

One serverBrowserSnip appPostgressame machine
Each part now gets a machine shaped for its job, and restarting or replacing the app no longer touches the data.
Text version

Change: The database moves to its own server

Added: Postgres.

Removed: Postgres.

New connections: Snip app → Postgres (over the network).

What Snip gains:

  • Each part sized for its job. The database gets memory and fast disks; the app gets CPU.
  • No more fighting. A busy app can't starve the database, and the other way round.
  • The app becomes replaceable. It holds no data, so you can rebuild it, redeploy it, or later run several copies, all pointing at the same database.

What it costs:

  • A network hop on every query: about half a millisecond inside one datacenter (01.04 Numbers to know). A redirect that makes one query barely notices; a page that makes 50 queries one after another does.
  • One more machine to pay for, patch and monitor.
  • Lower availability, for now. A redirect needs both machines. Two machines that are each up 99.9% of the time give about 99.8% together. Splitting things up doesn't remove single points of failure; it just separates them, so you can fix each one on its own. That's the next two lessons.

Step 2: up or out?

When a part runs out of room, there are two ways to grow it:

  • Scale up (vertical scaling): move it to a bigger machine, with more cores, memory or faster disks.
  • Scale out (horizontal scaling): add more machines and split the work between them.
Scale upScale out
Code changesNone: same program, bigger boxThe work must be splittable across machines
CeilingThe biggest machine you can buyVery high: keep adding machines
FailureStill one machine to failOne machine fails, the others carry on
CostPrice rises steeply at the very top endMany ordinary machines, plus something to spread work across them
Changing sizeUsually a restart or a switch to a new machineAdd or remove machines while running
ComplexityLowHigher: coordination, more moving parts

The usual answer: out for the app, up for the database

Most systems end up doing both, for a simple reason: things that hold no data scale out easily, and things that hold data don't.

Modern servers are very large, and a single well-tuned database goes much further than most people expect. Snip's estimate from 01.05 Back-of-the-envelope estimation (1,000 reads and 10 writes a second at peak, 300 GB) fits on a mid-sized database server with years of room.

Don't forget the standby

Scaling up still leaves the database as a single point of failure. The standard fix is a standby: a second database server that receives every change from the main one (the primary) and can take over within seconds to minutes if the primary dies. That swap is called failover.

It doesn't add capacity, and it costs a whole second server that mostly waits. But it means a dead disk is a short blip instead of hours of restoring from backup. You'll see how it works, and what can go wrong, in 04.07 Replication: leaders, followers and lag.

Seen in production

Let's Encrypt

2021

Certificate authority database

Let's Encrypt runs its certificate authority against a single MariaDB database "to minimize complexity", sending some reads to replicas. In late 2020 it moved the primary from a 24-core, 1 TB RAM server with SATA SSDs to a 64-core, 2 TB RAM server with NVMe drives. Primary CPU dropped from over 90% to about 25%, and the median API response went from about 90 ms to about 9 ms. They note they may need to shard eventually, but hardware advances have let them avoid it so far.

What we foundA service securing hundreds of millions of websites chose a bigger single database over splitting its data, and got a tenfold latency improvement.

The Next Gen Database Servers Powering Let's Encryptletsencrypt.org ↗
Predict first

Snip's database is at 85% CPU at peak, and most of that load is writes. There's plenty of budget. What's the simplest next step?

Commit to an answer before you read on.

Recap

Interview questions

JuniorfreqMust-knowConcept

What's the difference between vertical and horizontal scaling? When would you choose each?

Report a mistakeEdit this page