9 min read
System Design Index
Start Here
Tier 1 -- Building Blocks
Scale Reads
Scale Writes
Database Selection
Traffic Control
Consistency & Coordination
Estimation
Tier 2 -- Core Systems
Tier 3 -- Location & Real-Time
Tier 4 -- Infrastructure & Data
Tier 5 -- Finance & Commerce
Tier 6 -- Advanced & Collaborative
System Design Index
Start Here
Tier 1 -- Building Blocks
Scale Reads
Scale Writes
Database Selection
Traffic Control
Consistency & Coordination
Estimation
Tier 2 -- Core Systems
Tier 3 -- Location & Real-Time
Tier 4 -- Infrastructure & Data
Tier 5 -- Finance & Commerce
Tier 6 -- Advanced & Collaborative
Sharding & Partitioning (Hash-based, Range-based, Geo-based)
Tier 1 — Building Block
1. What Is It?
(also called horizontal ) splits a large dataset across multiple database nodes, where each node owns a disjoint subset of the data. Each node is called a shard. Collectively the shards form one logical database.
The problem solves: a single database node has a physical ceiling. A single PostgreSQL instance on the largest cloud VM handles ~30K writes/sec and stores up to a few TB before performance degrades. When your dataset is 100TB and your write rate is 500K/sec, no single node can handle it. Sharding distributes both storage and compute across N nodes, multiplying write and storage capacity by N.
is the same concept applied within a single database node (e.g., PostgreSQL table partitioning splits a large table into smaller physical files). Sharding is partitioning across multiple machines.
Your company's backend database is a single PostgreSQL instance. Write traffic has grown to 400,000 writes/second and the dataset has reached 80TB. The database is severely degrading in performance. Which approach most directly addresses both of these bottlenecks simultaneously?
2. How It Works
The Core Mechanism
A shard key (partition key) is a column or set of columns used to determine which shard a given row belongs to. The routing function maps shard_key → shard_id.
Hash-Based Sharding
Shard assignment: shard_id = hash(shard_key) % N
For a 4-shard setup, user_id=42 → hash(42) % 4 = 2 → Shard 2.
- Pros: Uniform distribution (no hotspots if key is high-cardinality); simple logic
- Cons: Range queries across shards require scatter-gather (sending the query to all N shards in parallel and merging the results); resharding when adding nodes remaps many keys (use to mitigate)
Range-Based Sharding
Shard assignment: Predefined key ranges map to shards.
Shard 1: user_id 1 – 1,000,000
Shard 2: user_id 1,000,001 – 2,000,000
Shard 3: user_id 2,000,001 – 3,000,000
Or for time-series:
Shard 1: events with timestamp Jan–Mar 2024
Shard 2: events with timestamp Apr–Jun 2024
Shard 3: events with timestamp Jul–Sep 2024
- Pros: Range queries efficient within a shard (e.g., "all users 1M–1.5M" goes to one shard); contiguous
- Cons: Hotspot risk if a range is disproportionately active (e.g., all new users go to the latest shard — "" of new data); requires explicit rebalancing as ranges fill up
Geo-Based (Directory-Based) Sharding
Routes based on geographic region or an explicit lookup table.
Shard US-East: users where region = 'us-east'
Shard EU-West: users where region = 'eu-west'
Shard AP-South: users where region = 'ap-south'
- Pros: (user data stored near user); data residency compliance (GDPR)
- Cons: Uneven distribution if user population is geographically concentrated; cross-region queries are expensive
Cross-Shard Challenges
- Cross-shard JOINs: Must scatter to all relevant shards and join in the application layer. Expensive. Design shard key to keep related data on the same shard (e.g., all orders for a user on the same shard as the user).
- Cross-shard transactions: Require two-phase commit (2PC) — complex and slow. Avoid by designing to keep transactional data co-located.
Your team stores e-commerce orders in a sharded database using hash-based sharding on order_id. A product manager requests a feature that retrieves all orders placed within a specific date range (e.g., the past 7 days). What is the main performance concern with this query under hash-based sharding?
3. Variants & Comparisons
| Strategy | Distribution | Range Queries | Hotspot Risk | Rebalancing | Best For |
|---|---|---|---|---|---|
| Hash sharding | Uniform (if key is high-cardinality) | Scatter-gather across all shards | Low (hash scatters) | Hard (need consistent hashing) | Even distribution; point lookups; social media, events |
| Range sharding | Potentially uneven | Efficient within a shard | High (latest range = hot write target) | Easier (split a range) | Time-series data; analytics; ordered data access |
| Geo-based | Proportional to population | Within-region efficient | High (dense regions) | Hard | Regulatory compliance; user data locality |
| Directory/lookup | Flexible (lookup table defines mapping) | Possible if lookup is queryable | Configurable | Easiest (update lookup table) | Complex routing rules; migration-friendly |
| Consistent hash sharding | Uniform + minimal remapping | Scatter-gather | Low | Easy (1/N remapping on add/remove) | Dynamic cluster scaling |
Your team is building a time-series metrics platform that stores server telemetry data and frequently needs to query all data within a given time window (e.g., 'last 6 hours'). Which sharding strategy best fits this use case, and what is its primary trade-off?
4. When to Use It (and When NOT To)
Use Sharding When:
- Single DB node is the bottleneck: Write QPS exceeds ~20K/sec on a single node, or data size exceeds ~1TB with performance degradation
- Storage exceeds single-node capacity: Dataset too large for any single machine
- Data has a natural partition key:
user_id,order_id,tenant_id— a key that distributes data evenly and keeps related records together - Multi-tenant SaaS: Shard by
tenant_idto isolate tenant data and scale each tenant independently
Decision triggers:
- "If primary DB CPU > 80% on writes at peak → add shards to distribute write load"
- "If dataset > 2TB and growing → shard before single-node performance cliff"
- "If you have clear tenant/user isolation requirements → shard by tenant or user"
Do NOT Shard When:
- Read replicas or caching haven't been tried first: adds massive operational complexity. Cache + read replicas can handle 10–100× the traffic first.
- Your dataset fits on one node: is premature optimization for 95% of applications.
- You need frequent cross-shard transactions: Financial applications where every transfer spans two users (two shards) require 2PC everywhere. Consider a NewSQL database (Spanner, CockroachDB) that handles distributed transactions natively.
- You haven't chosen a good shard key: Sharding with a bad shard key (low cardinality, or creates hotspots) is worse than not sharding.
Anti-patterns:
- Shard by sequential auto-increment ID: All new writes go to the shard holding the highest range — creating a "hot shard." Use hash-based on a high-cardinality key instead.
- "Celebrity" hot shard: A few entities (viral posts, famous users) receive 1000× the traffic of normal entities, overloading their shard. Fix: shard by a secondary key, replicate hot entities, or use application-level routing to spread the load.
- Not co-locating related data: If
usersandordersare sharded separately by different keys, every order query that needs user data requires a cross-shard join. Shard both tables byuser_id. - Resharding without planning: Adding a shard to a
hash % Nsystem remaps N/(N+1) keys — nearly everything. Always use or range-based sharding when you anticipate adding nodes.
A fintech startup is building a peer-to-peer payment platform where every money transfer moves funds between two different user accounts. Their dataset is currently 50GB and fits comfortably on a single database node, but the engineering team is considering sharding by user_id to prepare for future growth. What is the most significant reason to avoid sharding in this situation?
5. Real-World Usage
Instagram (PostgreSQL by user_id): Instagram shards PostgreSQL by user_id using a hash function. All of a user's photos, follows, and activity are on the same shard — avoiding cross-shard joins for common operations. They use a custom Python library (django-) to route queries. Each shard is a PostgreSQL instance with primary + replica. The shard key is embedded in all object IDs (the Snowflake variant Instagram uses encodes shard ID in the ID itself).
Cassandra (automatic hash sharding via ): Cassandra automatically shards data across nodes using on the partition key. The application specifies the partition key in the data model; Cassandra's token ring handles the rest. Adding nodes rebalances automatically with minimal disruption. Cassandra also replicates each partition to R nodes ( factor) for — sharding and are unified in one system.
Vitess (MySQL sharding for YouTube/Slack): Vitess adds a sharding layer on top of MySQL. The Vitess router intercepts SQL queries, inspects the WHERE clause for the shard key, and routes to the correct MySQL shard. Cross-shard queries are executed as scatter-gather. YouTube (800M+ videos), Slack, and GitHub use Vitess to scale MySQL horizontally beyond what a single node can handle.
A social media platform shards its PostgreSQL database by user_id and embeds the shard ID inside every generated object ID. A developer notices that fetching a user's posts, followers, and recent activity never requires querying multiple shards. What is the primary design decision that makes this possible?
6. Interview Cheat Sheet
Key sentences to demonstrate depth:
- " distributes data across N nodes by on a shard key — my first question is always: what is the shard key, and does it give uniform distribution without creating hot shards?"
- "Hash gives uniform distribution and prevents hotspots, but destroys range query efficiency — scatter-gather to all N shards is O(N) cost. Choose based on your dominant access pattern."
- "The cardinal rule: keep data that's queried together on the same shard. If users and orders are always queried together, shard both by
user_id. Cross-shard JOINs kill performance." - "Resharding is the nightmare scenario — adding a shard to a
hash % Nsystem remaps almost everything. Avoid by using from the start, or range sharding with explicit split points." - "Before recommending sharding, I always ask: have you tried caching, read replicas, and query optimization? Sharding multiplies operational complexity — it's a last resort, not a first resort."
Common follow-up questions:
| Question | Concise Answer |
|---|---|
| "What is a hot shard and how do you fix it?" | A hot shard receives disproportionate traffic (e.g., all new users, a viral entity). Fix: split the hot shard (range-based), add more VNodes in consistent hashing, or replicate hot entities across multiple shards with a secondary lookup. |
| "How do you handle cross-shard transactions?" | Option 1: Avoid them by co-locating transactional data on the same shard. Option 2: Use 2PC (coordinator pattern — slow, complex, failure-prone). Option 3: Switch to NewSQL (Spanner, CockroachDB) which handles distributed transactions natively. |
| "What's the difference between sharding and partitioning?" | Partitioning = splitting data within one node (PostgreSQL table partitioning). Sharding = splitting data across multiple nodes. Both use the same partition key logic, but sharding adds network routing complexity. |
| "How do you choose a shard key?" | High cardinality (many distinct values); even distribution; queries typically filter on it; co-locates related data. Anti-pattern: low-cardinality keys (country = 200 shards max, US shard gets 40% of traffic). |
| "What if you need to shard an existing un-sharded database?" | Take a copy of the data; run a migration script to assign each row to a shard based on the new shard key; set up new shard infrastructure; do a dual-write period (write to both old + new); verify; cut over reads; decommission old. This is painful — plan sharding early. |
Connections to other building blocks:
- : The standard algorithm for hash-based sharding that minimizes remapping when adding/removing shards. Cassandra's token ring is consistent hashing applied to sharding.
- Unique : Snowflake IDs embed a shard/worker ID — IDs are globally unique across shards without coordination. Instagram's IDs encode the shard ID directly, enabling routing from ID alone.
- Read Replicas: Each shard typically has its own read replicas. Sharding handles write scale; replicas handle read scale within each shard.
- CAP Theorem: Cross-shard transactions force a CAP tradeoff. If you need shard A and shard B both to commit atomically, you need 2PC (CP) — or you sacrifice consistency (AP, via saga/compensation).
- Message Queues: partitions are sharding for log streams. The partition key (message key) determines which partition (shard) a message goes to, providing ordering within a partition.
Glossary History
Click dotted jargon to save explanations here.
Glossary History
Click dotted jargon to save explanations here.