Building Blocks · Partitioning and Consistent Hashing

Sharding and Consistent Hashing

Picking a shard key for the hot query, hash versus range partitioning, consistent hashing, hot partitions and queries that span shards.

  • 8 min read
  • 11 practice questions
On this page
  1. Description
  2. The shard key
  3. Hash versus range partitioning
  4. hash mod N, and why it hurts
  5. Consistent hashing
  6. Hot partitions
  7. Queries across shards
  8. Choosing a shard key: a checklist
  9. Check yourself
  10. Key takeaways
  11. Quick revise
  12. Practice

Description

Replication gives you more copies of the same data. Sometimes that isn't enough: the data itself, or the write load, outgrows one machine. A messaging app with 40 TB of messages and 80,000 writes a second can't fix that with replicas, because every replica would still store all 40 TB and apply every write. The data has to be split: each node - a shard, or partition - holds only a slice.

Splitting is the easy part. The hard part is splitting so that each request touches as few shards as possible, the load stays even, and you can add machines later without moving everything. In this lesson:

  1. The shard key - the one choice that decides the rest.
  2. Hash versus range partitioning.
  3. Why hash mod N hurts when you add a node, and how consistent hashing fixes it.
  4. Hot partitions, and splitting a single huge key.
  5. Queries and transactions that span shards.
  6. A checklist for choosing a shard key.

The shard key

Every row is assigned to a shard by its shard key. Choose it from the hot query:

  • "Messages in conversation X, newest first" → shard by conversation_id. Each conversation lives on one shard; reading it is a single-shard range scan.
  • Shard by sender_id instead and reading a conversation means gathering messages from every participant's shard.
  • Shard by timestamp and all of today's writes land on the same shard.

The key decides both locality (what can be read from one shard) and balance (whether load is even).

Hash versus range partitioning

Hash partitioningRange partitioning
Assign byhash(key)Key ranges (A-F, G-M, ...)
BalanceEven, for many keysUneven if keys cluster (e.g. by time)
Range scans across keysScatter to every shardEfficient - neighbors are together
Typical useUser IDs, conversation IDsTime-ordered data within a key, alphabetical ranges

Many systems combine them: hash on the first part of a compound key (conversation_id) and keep rows sorted by the second part (sent_at) within the partition.

hash mod N, and why it hurts

The simplest mapping is shard = hash(key) mod N. Adding a node changes N - and changes the answer for most keys. Going from 4 shards to 5, a key stays put only if h mod 4 = h mod 5, which happens for 4 of every 20 values of h mod 20: 80% of the data moves. For a 40 TB dataset that's a migration nobody wants.

Consistent hashing

Keys and nodes on a hash ring; each key belongs to the next node clockwise. Adding node E takes over only the arc between B and E, so only key k2 moves.

Put both nodes and keys on a ring (hash values from 0 to 2^32). A key belongs to the first node clockwise from its position. Adding a node claims only the arc between it and its predecessor - about 1/N of the keys (20% going from 4 to 5) - and nothing else moves. Removing a node hands its arc to the next one.

Two refinements make it practical:

  • Virtual nodes. Each physical node takes many positions on the ring (say 100). Arcs even out statistically, bigger machines can take more positions, and when a node fails its many small arcs are spread over all the others instead of doubling one neighbor's load.
  • Replication along the ring. Store each key on the next few distinct nodes clockwise, so losing one node loses no data.

Cassandra, DynamoDB and many caches use this scheme.

Hot partitions

Even with a good key, some partitions run hot:

  • Time-ordered range keys send every new write to the newest range. Hash the key or put a hashed prefix before the timestamp.
  • One enormous key - a celebrity's follower list, a viral post's like counter - lives on one shard whatever the scheme; consistent hashing can't split a single key. Split it yourself: write to likes:post42#0..#15 (a random sub-key per write) and sum the sub-keys on read, or handle the few huge keys with a separate path.

Queries across shards

A query by anything other than the shard key has two options:

Users in Boston?
(not the shard key)

Shard 1

Shard 2

Shard 3

Users in Boston?

Index by city
Boston: users 7, 19, 42

Users in Boston?
(not the shard key)

Shard 1

Shard 2

Shard 3

Users in Boston?

Index by city
Boston: users 7, 19, 42

  • Scatter-gather: send it to every shard and merge the results. Fine for rare admin queries; expensive for hot paths, and its latency is the slowest shard's.
  • A global secondary index: a second table partitioned by the other attribute (users by city → shard by city, listing user IDs), updated asynchronously when users change. Fast reads, eventually consistent.

Transactions across shards - moving money between two accounts on different shards - need a distributed protocol: two-phase commit (a coordinator asks both to prepare, then commit; blocking if it fails mid-way) or a saga (a local transaction on each shard, with compensating actions if a later step fails). Both cost latency and complexity, which is the real reason to choose a shard key that keeps common operations on one shard.

Choosing a shard key: a checklist

QuestionGood sign
Does the hottest query include the key?Yes - it's served by one shard
Do common multi-row writes share the key?Yes - no cross-shard transactions
Are there many distinct key values?Millions - load can spread
Is any single key huge or very hot?No - or it has a plan (sub-keys)
Is the key monotonic (time, sequence)?No - or it's hashed first
Will the key ever change for a row?No - moving a row between shards is expensive

Going further. The deep dive (next tab) simulates how even the load really is with and without virtual nodes, measures how much data moves under each scheme, and covers jump and rendezvous hashing, logical partitions, online resharding, and the real cost of two-phase commit versus sagas.

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. Why is consistent hashing better than hash mod N when you add a node?

Show answer

hash mod N changes almost every key's shard when N changes (80% of keys move from 4 to 5 nodes). Consistent hashing moves only the keys in the new node's arc - about 1/N.

2. Orders are range-partitioned by created_at month. Where do today's writes go?

Show answer

All to the shard holding the current month - one hot shard while the others sit idle for writes. Hash-partition by order or customer ID instead (and keep time as a sort key within the partition).

3. Users are sharded by user ID. How do you serve "all users in Boston" quickly?

Show answer

A global secondary index partitioned by city (city → user IDs), updated asynchronously as users change - or accept a scatter-gather query across all shards if it's rare.

Key takeaways

  • Shard when data or writes outgrow one node; replicas don't help there.
  • The shard key follows the hot query - locality first, balance second.
  • Hash partitioning balances; range partitioning keeps neighbors together but can create hot shards.
  • hash mod N moves most keys on resize; consistent hashing moves about 1/N. Use virtual nodes.
  • A single huge key stays hot - split it into sub-keys.
  • Off-key queries scatter or use a global index; cross-shard writes need 2PC or sagas.

Quick revise

The whole skill on one page, for the night before an interview.

Everything from the lesson and the deep dive on one page. Skim it before a design interview, and open the full lesson for anything that doesn't ring a bell.

Choosing a shard key

QuestionGood sign
Does the hottest query include the key?Yes - one shard serves it
Do common multi-row writes share the key?Yes - no cross-shard transactions
Many distinct values?Millions - load can spread
Any single key huge or very hot?No - or it has a plan (sub-keys)
Monotonic (time, sequence)?No - or it's hashed first
Can a row's key change?No - moving rows between shards is expensive

Example: "messages in conversation X, newest first" → shard by conversation_id, sort by sent_at within the partition.

Hash vs range

HashRange
BalanceEven across many keysUneven if keys cluster (time)
Range scans across keysScatter to every shardEfficient
TypicalUser / conversation IDsTime order within a key

How much moves when you add a node

Scheme10 → 11 nodesNotes
hash mod N91% of keys (80% for 4 → 5)Almost a full migration
Consistent hashing, 100 vnodes~8-9%Only the new node's arcs
Jump consistent hash9.1% (the minimum)Buckets only added/removed at the end

Cross-shard work

  • Off-key queries: scatter-gather (latency = slowest shard; fine when rare) or a global secondary index partitioned by the other attribute (fast, eventually consistent).
  • Cross-shard writes: two-phase commit (atomic, blocks if the coordinator fails) or a saga (local steps + compensations, no isolation).
  • Best of all: a shard key that keeps common operations on one shard.

The traps

  • Shard by timestamp - every new write hits the newest shard.
  • Shard by the wrong entity (sender_id when you read by conversation) - every read scatters.
  • One enormous key stays on one shard whatever the scheme - split it (likes:post42#0..#15, sum on read).
  • hash mod N turns a node addition into a migration of almost everything.
  • One ring position per node - shares vary by more than 2×.

Staff-level points, one line each

  • One position per node: busiest 2.26× average, emptiest 0.06×. 100 virtual nodes: 1.20× / 0.88×. Plan capacity for the busiest node, not the average.
  • Logical partitions: hash keys to a fixed, large number of partitions (Redis Cluster: 16,384 slots), map partitions to servers. Keys never rehash; rebalancing moves whole partitions; the partition count caps your spread - choose it generously.
  • Jump hash: no memory, perfectly even, minimal movement - but only for storage that grows at the end. Rendezvous hashing: highest hash(key, node) wins; any node can leave. Maglev: a lookup table for load balancers.
  • Online resharding: copy a snapshot → catch up with CDC → verify counts and checksums → brief cut-over (pause, confirm, flip routing) → clean up. Changing the shard key itself needs dual writes, backfill and a compare period - a one-way door.
  • 2PC blocks: a participant that voted yes can't decide alone and holds locks until the coordinator answers. Spanner and CockroachDB make the coordinator's decision durable over consensus.
  • Sagas expose intermediate states (an order placed, payment failing later), so steps must be idempotent and compensations must eventually succeed. Standard across microservices; 2PC is standard inside one distributed database.
  • Hot keys: detect per key/partition (not per-node averages), split writes, replicate reads, and isolate outliers (celebrities, the tenant that's 40% of the data) on their own partitions or path.

Say it in an interview

  • "Shard by conversation ID, sorted by time within it - reading a thread is one shard and one range scan."
  • "Keys hash to 16,384 logical partitions, so adding servers moves partitions, never individual keys."
  • "A transfer between two customers would need 2PC or a saga, so I'd shard by customer to keep their accounts together."
  • "The viral post's like counter gets 16 sub-keys, summed on read."

Practice

This skill comes with 11 multiple-choice questions that tell you which misconception a wrong answer reveals. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Sharding and Consistent Hashing free

Practice Sharding and Consistent Hashing free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime