Skip to content
Naveen Raj

System Design Fundamentals · The Data Layer

Replication and Sharding

A single database server eventually runs out of capacity in one of two ways: it can't keep up with reads, or it can't keep up with writes (or store all the data). Each has a different fix.

Replication — fixes read capacity and availability

Copy the full dataset onto multiple machines. The classic setup is primary-replica: all writes go to one primary, which streams changes to one or more read replicas.

                 writes
                   ↓
              ┌─────────┐
              │ Primary │
              └────┬────┘
         replication stream
        ┌──────────┼──────────┐
        ↓          ↓          ↓
   ┌─────────┐┌─────────┐┌─────────┐
   │Replica 1││Replica 2││Replica 3│  ← reads
   └─────────┘└─────────┘└─────────┘

This solves two problems at once: read traffic can be spread across replicas (horizontal read scaling), and if the primary dies, a replica can be promoted, giving you availability. It does not solve write capacity — every write still goes through one primary — and replication is typically asynchronous, meaning replicas can briefly lag behind (more on why that's often an acceptable trade-off in the next section).

Sharding — fixes write capacity and storage size

Split the dataset itself across multiple databases, each holding a subset of the rows, based on a shard key.

        writes for user 1-1000     writes for user 1001-2000
                 ↓                          ↓
            ┌─────────┐                ┌─────────┐
            │ Shard A │                │ Shard B │
            └─────────┘                └─────────┘

Now write capacity scales with the number of shards, since each shard only handles its own slice of traffic. The hard part is picking the shard key — a bad key creates a "hot shard" that gets disproportionate traffic (e.g. sharding a social app by signup date means all of today's active users hit one shard). A good shard key distributes both storage and load evenly, and ideally keeps data that's queried together on the same shard, since cross-shard queries (and especially cross-shard transactions) are expensive and often require the application to stitch results together itself.

Replication and sharding are usually combined, not chosen between: shard for write/storage scale, then replicate each shard for read scale and availability.