Replication & Scaling

How databases scale reads and survive failures — primary-replica, sharding, and consistency trade-offs

Why

A single database server has a ceiling on how many queries it can serve. Replication and sharding are the two primary ways to scale beyond that ceiling. They come with real trade-offs — replication lag, split-brain risk, cross-shard query complexity — that show up directly in day-to-day architectural decisions.

Intuition

Replication copies the same data to multiple servers. Scale reads by routing to replicas; primary handles all writes. The replica always lags behind the primary — a write isn't visible on the replica until the WAL is applied. This lag is the source of "I just wrote this, why can't I read it?" bugs in applications that read from replicas.

Sharding splits the data itself across multiple servers, each responsible for a subset of rows. Scales both reads and writes, but makes cross-shard joins, transactions, and aggregations much harder.

Explanation
Primary-replica replication
Primary (leader) ├── receives all writes ├── streams WAL to replicas └── can also serve reads (at the cost of extra load) Replica (follower) × N ├── replays WAL — eventually consistent with primary ├── serves read queries (may be slightly stale) └── can be promoted to primary on failover Sync vs Async replication: Synchronous: primary waits for at least one replica to confirm before acknowledging the write → no data loss on failover → higher write latency Asynchronous: primary acknowledges immediately, replica catches up → lower write latency → small data loss window on crash

Read replicas are the first scaling step for read-heavy applications. Route analytics, reporting, and non-critical reads to replicas; route writes and critical reads (e.g., payment confirmations) to the primary. Design applications to tolerate replica lag — don't read-your-own-writes from a replica immediately after writing.

Sharding strategies
Range sharding
Rows with key in range [A–M] go to shard 1, [N–Z] to shard 2. Range queries are efficient — all rows in a range live on one shard. Risk: hot spots if one range is accessed far more than others.
Hash sharding
shard = hash(key) % N. Even distribution — eliminates hot spots. Range queries span all shards — expensive. Resharding when adding nodes requires remapping keys — consistent hashing minimises this.
-- Cross-shard challenges: -- JOINs across shards require fetching from multiple servers -- Distributed transactions (2PC) are slow and complex -- Aggregations must be computed per-shard and merged -- Unique IDs must be globally unique — use UUIDs or Snowflake IDs