Art of Codeartofcode
LLeeaarrnniinngg
BBlloogg
TToooollss
GGaammeess AArreennaa
JJoobbss
LLiivvee CCoouurrsseess

Courses

  • System DesignHigh-level system design, one everyday scene at a time: 30 concepts and 15 interview rounds.712 lessons
All coursesTutorialsMy Learning

Categories

  • 01AI & Tools
  • 02Tutorials
  • 03Engineering
  • 04Reviews
  • 05Build Logs
  • 06Tales of Misfits
  • 07Opinion
  • 08Career
  • 09News

Read & write

All storiesEvery post, newest first.Write for usPublish your stories and earn from what you write.Writer leaderboardsWho is writing the most read posts.

Categories

  • PDF Tools25
  • Development09
  • Utilities10
  • Design04
  • Converters04
  • Generators02

Featured

JSON FormatterFormat, validate and minify JSON.Regex TesterTest patterns against live text.Merge PDFCombine PDFs in your browser.JWT DecoderRead a token’s header and claims.Password GeneratorStrong passwords, generated locally.Gradient GeneratorBuild CSS gradients visually.
All 53 tools

Play a round

DevdleOne developer word a day, six guesses.Python RushClassic snake, with coding icons to eat.Blink or BreakA quick test of your reflexes.
Games Arena

Learn with us

Live CoursesInstructor-led courses. Join a waitlist and be first in when one starts.LearningStructured programming courses with AI assistance and certificates.

System Design

15. Sharding

Lesson 13 of 15

15. Sharding

1
The picture to keep in your head
2
15.1 Why shard at all?
3
15.2 How do you choose the shard key?
4
15.3 What are the ways to map keys to shards?
5
15.4 What is a hot shard?
6
15.5 How do you add shards without moving everything?
7
15.6 What happens to queries and joins that cross shards?
8
15.7 How do you keep IDs and unique rules across shards?
9
15.8 How do sharding and replication work together?
10
Memory card and where the analogy breaks
11
Practice: five levels
12
Interview questions
13
Solutions
14
Sources
15
Code lab
15. Sharding

Solutions

3 min read+10 XP

Solutions

Level 1

reveal

Level 2

reveal

Level 3

reveal

Level 4

reveal

Level 5 (sketch)

reveal

No tracks available

Lofi Player

artofcode

artofcode.in

The den of devs.

Stories, tools, games, and gear for developers.

Read the StoriesEExxpplloorree TToooollss
Art of Codeartofcode

Platform

  • BBlloogg
  • TToooollss
  • GGaammeess AArreennaa
  • CCoouurrsseess
  • LLeeaarrnniinngg
  • CCaammppuuss

Company

  • AAbboouutt UUss
  • JJoobbss && IInntteerrnnsshhiippss
  • CCoonnttaacctt

Legal

  • TTeerrmmss ooff SSeerrvviiccee
  • PPrriivvaaccyy PPoolliiccyy
  • RReeffuunndd PPoolliiccyy

Copyright © 2026 artofcode.in, All Rights Reserved.

IST·--:--

1Show the Level 1 solution
2**A.**
31. **Bad.** Few values and very uneven (a few countries hold most users).
42. **Good.** Many values, even spread, and most order queries include the user.
53. **Bad** under range sharding: every new event goes to the newest shard. Use a hashed key or `(source, time bucket)`.
64. **Mixed.** Fine for the 5,000 small tenants, but the 3 huge ones become hot. Use directory routing to give each big tenant its own shard.
75. **Bad.** A handful of values, and most orders share one status.
8
9**B.**
101. **One shard** (the user's).
112. **Every shard** (or a precomputed counter or analytics store).
123. **Every shard**, unless the order ID contains the shard or you keep an `order_id → shard` index. That's why IDs with the shard inside are handy.
134. **One shard.**
Show the Level 2 solution
1. 2,000,000,000 × 1 KB = 2 TB ÷ 250 GB = **8 shards**; × 3 copies = **24 servers**.
2. 20,000 ÷ 8 = **2,500 a second** per shard. At 40% on one shard: **8,000 a second**, more than three times its fair share.
3. Mod N: about **80%** (4 out of 5). Logical shards: about **20%** (1 out of 5), moved as whole buckets.
4. 1 − 0.99¹⁶ ≈ **15%** of dashboard loads.
1Show the Level 3 solution
2Tested solution (Python 3), the key part:
3
4```python
5class LogicalShardRouter:
6    def __init__(self, n_logical, servers):
7        self.n_logical = n_logical
8        self.owner = {ls: servers[ls % len(servers)] for ls in range(n_logical)}
9
10    def logical(self, key):
11        return h(key) % self.n_logical          # fixed forever: keys never re-hash
12
13    def shard_for(self, key):
14        return self.owner[self.logical(key)]
15
16    def add_server(self, new_server):
17        servers = sorted(set(self.owner.values())) + [new_server]
18        target = self.n_logical // len(servers)
19        per_server = Counter(self.owner.values())
20        moved = 0
21        for ls in range(self.n_logical):        # hand whole buckets to the new server
22            old = self.owner[ls]
23            if per_server[old] > target and per_server[new_server] < target:
24                self.owner[ls] = new_server
25                per_server[old] -= 1
26                per_server[new_server] += 1
27                moved += 1
28        return moved
29```
30
31All checks pass: growing from 4 to 5 servers moves **80%** of keys with mod N, and **20%** (204 of 1,024 buckets) with logical shards. The full file, including the range, hash and directory routers and scatter-gather, is in `code/ch15_sharding.py`.
1Show the Level 4 solution
2**The bug:** the shard key is **order date**, sharded by **range**. Every new order has today's date, so **all new orders go to the last shard**. During the sale, that shard takes 100% of the writes while the others hold old orders and sit idle. In the tested demo, all 10,000 of today's orders land on one shard.
3
4**The fix:** shard by a high-cardinality key that spreads writes, **hashed `user_id`**:
5
6```python
7def shard_for_order(order):
8    return logical_router.shard_for(order.user_id)
9```
10
11Now today's orders spread across all shards (about 2,500 each in the demo).
12
13**Monthly reports:** they now span every shard. Don't run them as scatter-gather on live shards; stream order changes into an **analytics store** (or a reporting replica of each shard) and run reports there (Chapter 22).
1Show the Level 5 (sketch) solution
21. **Shard key:** `user_id`, hashed into **1,024 logical shards** mapped to 8 physical shard groups at first. Orders, order items, payments and the cart share the key, so checkout is a single-shard transaction.
32. **Orders by book:** a global secondary index table `(book_id, order_id, user_id)` sharded by `book_id`, updated from the order change stream. **Reports:** change streams into an analytics warehouse; nightly reports run there.
43. **IDs:** Snowflake-style 64-bit order IDs with the logical shard number inside, so an order ID can be routed directly (Chapter 10). **Unique email:** an `emails` table sharded by email; sign-up claims the email first.
54. **Adding shards:** add a server, move whole logical shards to it (copy, catch up, switch the map, verify, delete) with Vitess or Citus-style tooling, one bucket at a time, off-peak.
65. **Replication:** each shard group has a leader and two replicas in three Mumbai zones (one semi-synchronous); European users read browsing data from asynchronous replicas in Frankfurt.
76. **Cross-shard transaction:** a gift order where Asha (shard 3) pays for an order delivered to Ravi (shard 6), and both accounts must be updated. Handle it with a **saga**: create the order and charge Asha on her shard, then record the gift on Ravi's shard; if the second step fails, run a compensating refund (Chapter 17).