Sharding and partitioning
Writes outgrow one machine; how you split the data decides which queries stay easy.
Somewhere past the first few million users, writes outgrow one machine — vertical scaling buys time, never escape. Sharding splits data across databases by a shard key, and the key choice is the whole game: it decides which queries stay single-shard (fast, transactional) and which become scatter-gather. Shard a social product by user ID and a profile page is one shard, but “everyone who liked this post” touches all of them. Choose the key from your top queries, not from aesthetics.
Placement has three standard answers: range (keys 0–999 → shard A: great for range scans, prone to hot ranges — today’s timestamps all land together), hash (uniform spread, range queries destroyed), and hash on a consistent-hashing ring with virtual nodes — the diagram — so that adding capacity moves ~1/N of keys instead of nearly all of them (mod N’s fatal flaw). Directory-based placement (a lookup service maps key→shard) buys the most flexibility at the cost of one more thing that can be down. The recurring diseases: hot shards (one tenant is 100× the rest — mitigate by salting that key or giving whales their own shard), cross-shard queries (pre-aggregate, or accept scatter-gather at the tail), cross-shard transactions (sagas, previous stage), and resharding — the migration you should design for on day one, because it is miserable to retrofit under load.