~learn.

Data at Scale, on one page.

Prints on a single A4 or Letter page. Download PDF opens your browser's print dialog: choose “Save as PDF”.

System Design Mastery · World 01 cheat sheet

Data at Scale

~/himanshufree course · himanshukukreja.in/learn

Day 1Partitioning Deep-Dive

Partitioning is how you scale writes. Vertical scaling hits a ceiling and read replicas don't fix write bottlenecks. Partitioning (sharding) splits data across machines, each owning a subset, so storage, throughput and memory add up.

Hash partitioning. hash(key) % N spreads keys evenly with an O(1) lookup, but range queries become scatter-gather across every partition, and changing N moves most keys.

Range partitioning. Contiguous key ranges keep a range query on one partition, but auto-increment IDs or timestamps send every new write to the last partition.

Directory partitioning. A lookup table maps keys to partitions: any key can go anywhere and rebalancing is a directory update, but the directory is a single point of failure and adds a lookup to every request.

Consistent hashing. Keys and nodes sit on a ring; a key belongs to the first node clockwise. Adding a node moves only about 1/(N+1) of keys, from one neighbour. Virtual nodes even out the load.

~80%of keys move from 4 to 5 partitions with hash % N
~99%move going from 100 to 101
~50%move when doubling 4 to 8, modulo's best case
1 GB · 100 QPSper partition minimum, or you're over-partitioned
Trade-off · Hash vs range partitioning
HashRange
DistributionEvenSkewed if keys aren't uniform
Range queriesScatter-gatherOne partition
Hot spotOne viral keyThe newest range
ReshardingModulo moves most keysSplit or merge a range
  • Partitioning by hash(user_id + timestamp): perfect spread, but no more queries by user_id alone.
  • Range partitions on auto-increment IDs or time, so every new write lands on one partition.
  • Over-partitioning early: 1000 partitions × 100 app servers = 100,000 connections.

Day 2Replication Trade-offs

Three reasons to replicate. Replicas buy high availability (fail over to a copy), read scaling (reads spread across copies; writes don't) and geographic latency (read from a nearby copy).

Sync, async, semi-sync. Sync waits for followers: no loss, slower writes. Async acks at once: fast, but a dead leader loses unreplicated writes. Semi-sync waits for one follower: the production middle ground.

Quorums. With N replicas, if W + R > N every read overlaps the latest write. N=3 with W=2, R=2 is strongly consistent; W=1, R=1 is faster but only eventual.

Replication lag anomalies. Lagging followers break read-your-writes (your update vanishes), monotonic reads (data goes back in time) and consistent prefix (a reply shows before its message).

Split brain needs fencing. A network partition can leave two leaders accepting writes. Fence the old one: STONITH, storage or network fencing, or a lease it must keep renewing in ZooKeeper or etcd.

99.9%one server: ~8.7 h down a year; two independent: 99.9999%, ~31 s
~200 km/mslight in fiber; Tokyo to Virginia ~55 ms each way
10–60 sfailover window in which writes fail
RF=3standard: survives one failure, quorum intact
Trade-off · Leader-follower vs multi-leader vs leaderless
Leader-followerMulti-leaderLeaderless
Writes go toOne leaderAny regional leaderW nodes
ConflictsNoneLWW, merge, app logicTimestamps, read repair
Breaks onLeader death, lagConflict resolutionClock skew, tail latency
  • Serving a balance, inventory count or permission check from an async replica.
  • Failing over without fencing the old primary: two primaries, conflicting data.
  • Last-write-wins across leaders: clocks disagree and writes silently vanish.

Day 3Rate Limiting at Scale

Limits must be counted together. With 50 servers each seeing a slice of a user's traffic, uncoordinated local counters let 100 requests through a 10-per-minute limit. Counts must be shared, synced or sticky.

Fixed window's boundary burst. One counter per window is simple and O(1), but a user can spend a full quota just before and just after the boundary: 2x the limit within seconds.

Sliding window counter. Weight the previous window by its overlap and add the current one: (8 × 75%) + 3 = 9. Two counters per key, no boundary burst; the default for API limits.

Token bucket allows controlled bursts. Tokens refill at a fixed rate up to a capacity and each request spends one: the long-term rate is bounded, bursts up to capacity pass. Compute refill from elapsed time.

Fail open or fail closed. When the limit store dies, over-allow user-facing and paid APIs; under-allow DDoS protection, cost control and login. A conservative local fallback sits in between.

2xeffective rate at a fixed-window boundary
+1–2 msper check against a central Redis counter
~33%of keys unreachable when one node of a 3-node Redis cluster dies
10–30 sRedis Cluster automatic failover
Trade-off · Distributed counting
Central RedisLocal + syncSticky sessions
AccuracyHighApproximateHigh per server
Latency+1–2 msVery lowVery low
On failureTotal failure if Redis is downContinues on local limitsFailover disruption
  • Each server counting alone: users spread requests and multiply the limit.
  • One blanket fail-open rule: an AI call costing $0.01 each should fail closed.
  • Leaky bucket for user-facing limits: it queues requests and adds latency even with spare capacity.

Day 4Hot Keys and Skew

Traffic follows Zipf's law. The nth most popular key gets about 1/n of the top key's traffic. With 1,000 keys the top 1% take ~40%; viral content pushes the top 0.01% past 90%.

Detect with a Count-Min Sketch. Fixed memory, O(depth) per update: hash the key into several counters and read the minimum. It may overestimate but never underestimates, which is all hot key detection needs.

Layer the defenses for hot reads. CDN edge, then local app memory, then Redis with split keys and request coalescing; the database sees only misses. In the lesson, traffic past the edge drops from 10,000 to ~2,800 req/s.

Write-heavy hot keys can't be cached. Buffer increments and flush periodically, shard the counter across N keys (reads sum all N), or use a G-Counter CRDT where each node owns its own count.

Bifurcate by popularity. Celebrities get their own code path: posts from accounts under 10K followers are pushed into feeds; celebrity posts are pulled at read time and merged. Show approximate counts like "1.2M likes".

0.01%of URLs taking 90% of traffic in the redesign
>1000xaverage key traffic, or >10% of a partition: problematically hot
P99 500 → 20 msafter multi-layer hot key handling
10K followerspush on write below, pull on read above
Trade-off · Hot key strategies
Best forConsistencyWrite cost
CachingRead-heavy, stale OKEventualNone
Key splittingRead-heavy, rare writesWeakHigh fan-out
Local cacheUltra-low latencyWeakInvalidation
CoalescingMisses, cold startsStrongNone
  • Assuming uniform traffic: one viral key turns a partition into a single-node bottleneck.
  • Letting a hot key expire all at once: thousands of requests stampede the database.
  • Splitting keys that are written often: every write fans out to all splits.

Day 5Session Store Design

Sessions are read-heavy and forgiving. Every request validates a session (80% reads), so latency must stay under 5 ms P99. Durability is best effort: a lost session means logging in again, inconvenient but not catastrophic.

Sticky vs distributed sessions. Sticky sessions keep state in one server's memory: fastest, but a server failure logs its users out and deploys lose sessions. A distributed store (Redis) costs a network hop and survives both.

Client-side sessions can't be revoked. A JWT or encrypted cookie needs no storage and scales anywhere, but you can't invalidate it before expiry, it's capped at 4 KB and rides on every request.

Region-affine sessions. Encode the home region in the session ID (sess_east_abc123) and route there. If a region dies, its users re-authenticate; make that painless with SSO or remember-me.

Session security basics. 256-bit random IDs, a fresh ID on login to block fixation, and cookies set HttpOnly, Secure and SameSite=Lax.

10M × 2 KB = 20 GBfits in memory on a few servers
2–3M reads/srealistic peak: 20–30% of sessions active
6 shards × 2 = 12 nodesthe Redis Cluster plan, ~3.3 GB a shard
16384Redis Cluster hash slots
Trade-off · Redis Cluster vs DynamoDB for sessions
Redis ClusterDynamoDB
LatencySub-ms (0.2–0.5 ms)5–10 ms
DurabilityMemory-only by defaultReplicated across AZs
OperationsYou run the clusterFully managed
Multi-region writesExtra toolingGlobal Tables
  • Local session caches without short TTLs or pub/sub invalidation: logged-out sessions keep working.
  • A user_sessions set without the sessions' TTL: it fills with expired IDs.
  • Sequential, guessable session IDs instead of secure random ones.

BossDesign a URL Shortener at Scale

Clarify, then estimate. Ask before designing: spikes, code alphabet, duplicate URLs, analytics freshness, API rate limits. The answers set the target: 120,000 redirects/s during viral spikes.

Pre-allocated key ranges. A key service hands each API server a range of 10,000 counter values, scrambled and base-62 encoded to 7 characters. Only range allocation needs coordination; a crash just loses a few thousand codes.

Split redirect from creation. Redirects are 10x writes and need 99.99% uptime, creation 99.9%. Separate services scale and fail independently, and clicks go to Kafka asynchronously so counting never slows a redirect.

Hybrid sharding. URLs live on shards chosen by consistent hashing on short_code (fast redirects); a light user_urls index sharded by user_id serves "my URLs". Every create writes both.

62^7 ≈ 3.5 trillion7-character codes; 182.5B needed in 5 years
~1,160 / 11,600 per saverage creates / redirects
~500 bytesper URL with indexes; ~300 TB over 5 years replicated
>95%CDN hit rate for hot URLs
Trade-off · Consistency by operation
ConsistencyWhy
Create URLStrong (primary)Must not lose writes
RedirectEventual (any replica)Speed is critical
My URLs listRead-your-writesUsers expect their URLs
Delete URLStrong + cache invalidationMust take effect now
  • Auto-increment codes (predictable), random-then-check (races) or UUIDs (36 characters, not 7).
  • A bare 301 redirect: browsers cache it forever, hiding clicks and ignoring deletes.
  • Caching URLs without their expiry, so expired links keep redirecting.