Data Partitioning & Sharding
When data outgrows a single machine, you need to partition (shard) it across multiple nodes. This module covers the strategies, trade-offs, and production patterns for effective data distribution. Think of partitioning like organizing a library: you could put all books on one giant shelf (single node), but eventually you run out of space and it takes too long to find anything. Instead, you split books across rooms — fiction in Room A, non-fiction in Room B, reference in Room C. The challenge is choosing the split so that most visitors only need to visit one room, and no single room is overwhelmed while others sit empty.Module Duration: 10-14 hours
Key Topics: Hash Partitioning, Range Partitioning, Consistent Hashing, Rebalancing, Hot Spots
Interview Focus: Partition key selection, secondary indexes, cross-partition queries
Key Topics: Hash Partitioning, Range Partitioning, Consistent Hashing, Rebalancing, Hot Spots
Interview Focus: Partition key selection, secondary indexes, cross-partition queries
Why Partition?
Partitioning Strategies
Hash Partitioning
Range Partitioning
Compound Key Partitioning
Consistent Hashing
Basic Consistent Hashing
Virtual Nodes
Implementation
Secondary Indexes
Local Secondary Indexes
Global Secondary Indexes
Rebalancing Strategies
Fixed Number of Partitions
Dynamic Partitioning
Advanced: Geo-Partitioning & Data Sovereignty
At Staff/Principal level, partitioning isn’t just about performance—it’s about compliance and locality. As laws like GDPR (Europe) and CCPA (California) become stricter, where data lives physically becomes a legal requirement.1. Locality-Aware Partitioning
In a global database (e.g., CockroachDB, Spanner, or YugabyteDB), you can pin specific partitions to specific geographic regions.- The Goal: Keep data close to the user to minimize speed-of-light latency and comply with data residency laws.
- The Mechanism: Using “Placement Policies” or “Partitioning Tags.”
2. Follow-the-Workload (Dynamic Migration)
Sophisticated systems can dynamically move partitions based on the time of day or access patterns.- Daylight Shifting: Move active user data to the “waking” hemisphere to ensure local low-latency access.
- Access Locality: If a user from Germany suddenly starts accessing a “US East” partition frequently, the system can migrate that partition (or a replica) to “EU West” automatically.
3. Data Sovereignty Challenges
When data is pinned to a region, Cross-Region Operations become extremely complex:- Global Joins: Joining a “pinned” German user with a “pinned” Japanese order requires cross-continental network hops (200ms+).
- Global Secondary Indexes: If the index is global, writing to the German partition might require updating an index node in the US, breaking sovereignty if the index contains PII (Personally Identifiable Information).
Staff Tip: When designing for Global Scale, “Data Residency” is often a harder constraint than “Queries Per Second.” Always ask: “Does this record have a legal right to leave this continent?”
Hot Spots and Skew
Identifying Hot Spots
Hot Spot Mitigation
Cross-Partition Operations
Scatter-Gather Pattern
Cross-Partition Transactions
Interview Practice
Q1: Design partition key for Twitter
Q1: Design partition key for Twitter
Question: How would you partition Twitter’s tweet storage?Requirements Analysis:
- Queries: Get user’s tweets, home timeline, search
- Scale: 500M tweets/day, 200M users
Q2: Handle celebrity hot spots
Q2: Handle celebrity hot spots
Question: A celebrity with 100M followers posts. How do you handle the hot spot?Solution:
Q3: Rebalancing without downtime
Q3: Rebalancing without downtime
Question: How do you rebalance partitions without downtime?Process:
Advanced Design Scenarios
Scenario 1: Designing Partitioning for an E‑Commerce Platform
You are designing the data model and partitioning for a large e-commerce platform (catalog, carts, orders, inventory, users, payments). Key workloads:- Product browsing and search
- User-specific operations (cart, wishlist, recommendations)
- Order placement and history
- Inventory management per warehouse/region
- Users, carts, wishlists: Partition by
user_id(hash or consistent hash)- “Get cart” and “get wishlist” → single partition
- Cross-user queries (analytics) use separate OLAP or stream to a warehouse
- Orders: Partition by
user_idororder_id(with correlation to user)- Materialize read models for “orders by user” and “orders by status” using CQRS/Event Sourcing
- Inventory: Partition by
(warehouse_id, product_id)- Allows local, warehouse-level operations and avoids cross-partition inventory transactions
- Search: Separate inverted index service (Elasticsearch / OpenSearch) with its own sharding
- Many OLTP queries become single-partition and fast
- Cross-entity queries (“top selling products globally”) handled via denormalized tables or separate systems
- Consistency for cross-partition operations handled via Sagas/2PC as needed
Scenario 2: Multi-Tenant SaaS Partitioning
You are building a multi-tenant SaaS where each tenant has its own users, projects, and data. Goals:- Strong data isolation between tenants
- Ability to move tenants between clusters or regions
- Ability to put large tenants on dedicated resources
- Database-per-tenant:
- Pros: Strong isolation, easy per-tenant backup/restore
- Cons: Operational overhead when tenants = 10k+
- Shared database, tenant_id in every row:
- Pros: Easier to operate at scale
- Cons: Harder to move tenants, noisy neighbor effects
- Hybrid:
- Small tenants: shared database with partitioning by
tenant_id - Large tenants: own database or shard, with routing table
- Small tenants: shared database with partitioning by
- Maintain a Tenant Catalog mapping
tenant_id → {cluster, database, partition_key} - Route each request through a Tenant Router that picks the correct connection before query execution
- For large tenants, use more partitions or dedicated clusters and update catalog accordingly
Scenario 3: Time-Series Platform (Metrics/Logs)
You are designing a time-series platform that ingests telemetry, metrics, or logs from millions of devices. Characteristics:- Very high write throughput (append-only)
- Queries are often time-bounded and per device / per stream
- Data retention and tiering (hot vs cold storage)
- Primary key:
(tenant_id, stream_id, time_bucket) - Partition by hash(tenant_id, stream_id); time is part of clustering key
- Create time buckets (e.g., daily or hourly) to allow range scans and efficient TTL/compaction
- If you partition by raw timestamp, “now” is a hot partition
- Instead, spread by
(tenant_id, stream_id)and keep time in the clustering key
- Recent buckets stored on fast nodes (SSD, high IOPS)
- Older buckets moved to cheaper storage (object store) with precomputed aggregates
Key Takeaways
Partition Key is Critical
Choose partition key carefully—it determines data distribution, query efficiency, and hot spot risk.
Consistent Hashing Enables Scale
Virtual nodes provide even distribution and minimal data movement when nodes change.
Secondary Indexes Have Trade-offs
Local = fast writes, slow reads. Global = fast reads, eventually consistent writes.
Avoid Cross-Partition Operations
Design data model to keep related data together. Cross-partition = expensive.
Next Steps
Data Systems
Deep dive into Spanner, Cassandra, DynamoDB internals
Transactions
Handle cross-partition transactions with 2PC and Saga
Interview Deep-Dive
How do you choose a partition key for a system that needs to support both point lookups and range scans efficiently?
How do you choose a partition key for a system that needs to support both point lookups and range scans efficiently?
Strong Answer:
- This is a fundamental tension in partitioning design. Hash partitioning gives you excellent point lookups (hash the key, go directly to one partition) and even data distribution, but destroys range scan ability because adjacent keys are scattered across partitions. Range partitioning preserves key order (enabling efficient range scans) but creates hot spots when access patterns cluster around certain key ranges.
- The solution is usually a compound partition key. For example, in a time-series system, partition by hash(device_id) and use timestamp as the clustering key within each partition. Point lookups by device_id go to one partition, and range scans for “device X, last 24 hours” are also single-partition because the timestamps are ordered within the partition.
- DynamoDB models this explicitly with its partition key (hash distributed) and sort key (range ordered within the partition). Cassandra uses a similar compound primary key model.
- The design rule: pick the partition key to match your most frequent query pattern, then use secondary indexes or materialized views for alternative access patterns.
A celebrity posts on your platform and generates a massive hot spot on one partition. How do you handle this in real time?
A celebrity posts on your platform and generates a massive hot spot on one partition. How do you handle this in real time?
Strong Answer:
- This is the “celebrity problem” or “thundering herd on a single key.” The partition holding the celebrity’s data receives 1000x normal traffic, exceeding its capacity while other partitions sit idle.
- Immediate mitigation: add a random suffix to the celebrity’s partition key, splitting their data across N sub-partitions (e.g., “celebrity123:shard_0” through “celebrity123:shard_99”). Writes are distributed randomly across sub-shards. Reads require scatter-gather across all sub-shards, but this is parallelizable and much better than overloading a single partition.
- Detection must be automated. Monitor per-partition QPS and latency in real time. When a partition’s QPS exceeds a threshold (e.g., 5x the average), automatically add it to a “hot key” list and enable sub-sharding for that key. This is a dynamic, not static, process — celebrities come and go.
- Caching is the complementary strategy. For read-heavy hot spots, place the celebrity’s data in a distributed cache (Redis Cluster, Memcached) with a short TTL. This absorbs the read storm without hitting the database. For write-heavy hot spots (likes, view counts), buffer writes in memory and flush to the database in batches (write coalescing).
Explain the trade-offs between local secondary indexes and global secondary indexes in a partitioned database.
Explain the trade-offs between local secondary indexes and global secondary indexes in a partitioned database.
Strong Answer:
- A local secondary index is co-located with the data partition. Each partition maintains its own index over its local data only. Writes are fast because the index update is a local operation within the same partition. But reads by the indexed attribute require scatter-gather across all partitions because any partition might have matching data. Read latency equals the slowest partition.
- A global secondary index is separately partitioned by the indexed attribute. A query like “find all users in NYC” goes to a single index partition, making reads fast. But writes are slow because inserting a record might require updating an index partition on a different node, which is either a distributed transaction (expensive) or eventually consistent (the index lags behind the data).
- Cassandra uses local indexes (materialized views with scatter-gather). DynamoDB uses global indexes (GSIs that are eventually consistent). Elasticsearch uses global indexing with near-real-time consistency.
- The decision depends on read/write ratio. If the workload is write-heavy and reads by secondary key are rare, local indexes are better. If the workload is read-heavy with frequent secondary key lookups, global indexes are better despite the write overhead.