What it is
Sharding splits one logical dataset across multiple database servers, each holding a subset of rows, because a single node can no longer handle the write throughput or the storage. It's horizontal partitioning taken across machines — as opposed to vertical partitioning, which splits by columns or tables. Each shard is usually itself replicated, so sharding and replication compose rather than compete.
Interviewers treat sharding as the standard deep dive once your capacity math exceeds one box — past roughly 5k–10k writes/s or a few TB on one node. The scoring is almost entirely on the shard key: whether you chose it from the dominant access pattern, whether you saw the hot-shard failure mode, and whether you know what you gave up. Sharding before the math demands it is itself a scored mistake.
The math says 30k writes a second, so one Postgres box is out — I'll shard by user_id with consistent hashing, which makes every user-scoped query single-shard, and I'll accept that global queries now fan out.
The picture
The variants and when to pick each
Hash-based — even spread, dead range queries
Route each row by hash(key) — via consistent hashing or a fixed set of logical partitions, never naive mod N (adding a node under mod-N remaps nearly every key). Distribution comes out even, and hot spots from key locality disappear.
The price is that adjacent keys land on different shards, so range queries become scatter-gather across every node. The production-grade refinement is fixed logical partitions mapped many-to-one onto physical nodes — Redis Cluster's 16384 slots — so rebalancing moves whole slots instead of rehashing keys.
Range-based — great scans, hot tails
Each shard owns a contiguous key range, so range queries hit one or two shards — the natural fit for time-series and anything scanned in key order.
The classic failure is the hot tail: if keys are time-ordered, every write lands on the newest shard while the rest idle. Fixes are compound keys (tenant first, time second) or salting the head of the key — both of which mean designing the key around the write distribution, not only the read pattern.
Directory-based and geo — flexibility with a dependency
A directory service maps key → shard explicitly. Maximum flexibility: move one noisy tenant to its own shard, rebalance without rehashing, place data wherever you like. The cost is a lookup on every request and a directory that becomes a critical dependency — it gets cached aggressively and replicated, or it becomes the outage.
Geo-sharding partitions by region — EU users on EU shards — which buys data locality and GDPR compliance, and makes cross-region queries the expensive exception. Uber-style designs geo-shard by city for exactly this reason.
The shard key is the whole decision
A good shard key has high cardinality, spreads load evenly, and aligns with the dominant access pattern — the queries you shard for become single-shard and fast, everything else becomes scatter-gather and slow. Say that sentence explicitly: "user-scoped queries fast, global queries slow" is the trade being made.
The canonical trap is the celebrity: shard tweets by user_id and one account with 100M followers cooks a single shard — the Justin Bieber problem. And know the full bill: no cross-shard joins (denormalise or join in the app), no cross-shard transactions (sagas or 2PC pain), and unique IDs need generating without a single counter.
Numbers worth memorising
| Shard trigger, writes | ~5k–10k writes/s on one node |
| Shard trigger, storage | ~2–4 TB comfortable per Postgres/MySQL node |
| Logical partition headroom | provision 2–4× current need in logical shards |
| Redis Cluster slots | 16384 fixed hash slots mapped to nodes |
| Scatter-gather cost | latency = slowest shard × every global query |
Where the interviewer pushes
The standard push is the hot shard: "you sharded Twitter by user_id — what happens to Justin Bieber?" The strong answer concedes the design honestly: his shard melts on reads, so celebrity content gets served from cache and fan-out paths rather than shard reads, or I switch the tweet store to shard by tweet_id and pay scatter-gather on profile timelines instead. The point being scored is that I can name which access pattern each key choice sacrifices — there is no key that wins both.
The second push is resharding: "you need to add shards without downtime — go." Weak answers say "consistent hashing" and stop. The full mechanics: with fixed logical partitions I move whole slots — double-write to old and new homes, backfill history, verify counts, cut reads over, drop the old copy. It's operationally scary and slow by design, which is exactly why I provisioned 2–4× logical shards up front — the best resharding is the one you deferred for three years.