When Replicas Aren't Enough
Read replicas help enormously with read-heavy workloads, but they don't solve the write problem. Every single write — every INSERT, UPDATE, DELETE — must still go to the one Primary server. If your write volume exceeds what one machine can handle (even after vertical scaling and query optimization), you need Sharding.
Breaking the Database Apart
Sharding means splitting your data horizontally across multiple completely independent database servers. Each server is called a Shard and owns a distinct subset of the data. No shard shares storage or compute with another — this is called a shared-nothing architecture.
To implement sharding, you must choose a Shard Key — a column (or combination of columns) used to determine which shard a given row belongs to. The choice of shard key is the single most consequential architectural decision in a sharded system. A bad shard key creates hotspots that defeat the entire purpose of sharding.
Sharding Strategies
How do you map a Shard Key value to a specific server?
1. Hash Sharding
Apply a hash function to the key and use modulo arithmetic to assign a shard.
shard_number = hash(user_id) % total_shards
- Pros: Distributes data very evenly across shards, preventing hotspots. Works well when access patterns are random.
- Cons: Terrible for range queries. Finding "all users created in the last 7 days" requires querying every single shard and merging the results — a scatter-gather query that is slow and expensive.
2. Range Sharding
Assign contiguous ranges of key values to specific shards.
Shard A: User IDs 1 – 1,000,000
Shard B: User IDs 1,000,001 – 2,000,000
Shard C: User IDs 2,000,001 – 3,000,000
- Pros: Excellent for range queries. You know exactly which shard(s) hold the data for a given range.
- Cons: Prone to hotspots. If you shard by
created_attimestamp, all new writes go to the "latest" shard while older shards sit idle. This is called a monotonically increasing key problem.
3. Directory-Based Sharding
Maintain a separate lookup table (the "directory") that maps every key to its shard location.
user_id 1001 → Shard B
user_id 1002 → Shard A
user_id 1003 → Shard C
- Pros: Maximum flexibility. You can move individual records between shards without changing the routing logic.
- Cons: The directory itself becomes a bottleneck and a single point of failure. Every query requires a directory lookup before it can be routed.
A common interview question is: "Why is user_id often a better shard key than created_at?" The answer is that created_at is monotonically increasing — all new writes always go to the shard holding the most recent time range, creating a write hotspot. user_id (especially when hashed) distributes writes evenly because users are active across all ID ranges simultaneously. The follow-up is: "What if a single user generates a disproportionate amount of data?" — this is the celebrity problem or hot key problem, and it requires special handling like sub-sharding that user's data or using application-level caching.