Skip to content

Lesson 5 of 9 · 22m

Sharding: Splitting the Write Bottleneck

When one primary isn't enough — hash-based vs range-based sharding, the rebalancing problem, and the design questions to answer before you shard.

Sharding is the last tool in the scaling kit — and rightly so, because it trades "one big simple system" for "many smaller complex systems." You shard when a single primary can't handle the write volume or the data size, not before.

Hash vs range sharding

Hash sharding — shard = hash(user_id) % N. Even distribution by construction; rebalancing is the hard part (adding a shard re-hashes ~everything). Consistent hashing reduces the reshuffle — each new shard claims a slice of the hash ring, only its neighbors' data moves.

Range sharding — shard = user_id / 1000000. Easy to add a shard (just a new range); the problem is hotspotting — the highest range (newest users) gets all the writes while old ranges sit idle.

Directory sharding — a lookup table maps keys to shards. Most flexible (move a key by updating a row); adds a single point of failure that you now have to make highly available.

What sharding breaks

  • Cross-shard queries — SELECT ... WHERE on a non-shard key probes every shard. Queries that were one index scan become scatter-gather.
  • Transactions — Postgres's two-phase commit exists, but cross-shard transactions are slow and fragile. Design to avoid them.
  • Auto-increment IDs — id can't be a serial anymore; use UUIDs or a coordinated ID generator (Snowflake-style).

The question that matters

Before sharding: "Can I solve this with a bigger box, better indexes, partitioning, or a different storage engine?" Sharding is for writes that exceed a single Postgres primary — usually >10k writes/sec sustained or >10TB per table. Below that, the other tools are simpler.

Field notes

  • Shard by the query pattern: if 90% of queries are WHERE user_id = X, shard by user_id — the shard key is the access pattern.
  • Resharding is the real cost — plan for it from day one, or shard count becomes a permanent constraint.
  • Vitess, Citus, and Citus-like extensions automate much of this — the "shard by hand" era is mostly over.