# System Design — Complete Notes

Prepared from the [takeUforward × InterviewReady System Design roadmap](https://takeuforward.org/system-design/complete-system-design-roadmap-with-videos-for-sdes).
Covers all 13 roadmap sections (~70 topics) as interview-focused notes, plus a practice-problems tracker and an ELI-10 revision.

**How to use in Claude chat:** paste or upload this file at the start of a conversation, then ask Claude to quiz you, expand any topic, or run a mock system-design interview using it as your knowledge base.

## Contents
- Basics
- Load Balancing
- DataStores
- Consistency vs. Availability
- Message Queues
- DevOps Concepts
- Caching
- Microservices
- API Gateways
- Authentication
- System Design Tradeoffs
- Practice Problems
- Quick Revision (Explained Like You're 10)


---

# Basics


# What is System Design?

> [!abstract] TL;DR
> System design is the process of defining the **architecture, components, interfaces, and data** of a system to satisfy specified requirements — especially non-functional ones like scale, latency, availability, and cost.

## Definition
System design turns a vague problem ("build Twitter") into a concrete blueprint: what services exist, how they talk, where data lives, and how the system stays fast and available as load grows.

## Functional vs Non-Functional Requirements
- **Functional** — *what* it does: post a tweet, follow a user, load a feed.
- **Non-functional** — *how well* it does it: latency, throughput, availability, consistency, durability, cost, scalability.

Interviews are won on the **non-functional** side — anyone can list features; the skill is reasoning about trade-offs at scale.

## Core concerns you always weigh
| Concern | Question it answers |
|---|---|
| Scalability | Does it hold up as users/data grow? |
| Availability | Is it up when users need it? (9s) |
| Latency / throughput | How fast, how much per second? |
| Consistency | Do all reads see the latest write? |
| Durability | Is committed data safe forever? |
| Cost | What does this architecture cost to run? |

## The universal trade-off
There is no "best" design, only trade-offs. The classic tension is **[[consistency]] vs [[availability]]** (CAP), and more broadly **performance vs cost vs complexity**. Say the trade-off out loud in interviews.

## Interview framework (memorize)
1. Clarify requirements + scope (functional + non-functional)
2. [[capacity-estimation|Estimate scale]] (QPS, storage, bandwidth)
3. Define API + data model
4. High-level design (boxes and arrows)
5. Deep-dive one or two components
6. Identify bottlenecks; scale them ([[caching]], [[horizontal-vs-vertical-scaling|replication/sharding]])

## Related
[[horizontal-vs-vertical-scaling]] · [[capacity-estimation]] · [[relational-databases]] · [[caching]]



# Horizontal vs. Vertical Scaling

> [!abstract] TL;DR
> **Vertical (scale up)** = a bigger machine. **Horizontal (scale out)** = more machines. Real systems scale out because a single box has a hard ceiling and no redundancy.

## The two directions
| | Vertical (scale up) | Horizontal (scale out) |
|---|---|---|
| How | Add CPU/RAM/disk to one node | Add more nodes |
| Ceiling | Hardware limit — finite | Effectively unlimited |
| Redundancy | Single point of failure | Survives node loss |
| Complexity | Simple, no code change | Needs [[caching\|load balancing]], coordination |
| Cost curve | Gets expensive fast | Commodity hardware, linear-ish |

## When to use which
- **Vertical** — early stage, stateful DBs that are hard to distribute, quick wins.
- **Horizontal** — anything that must be highly available or grow past one machine.

## What horizontal scaling requires
- A **load balancer** to spread requests across nodes.
- **Stateless services** where possible (session state pushed to a [[caching|cache]] or DB) so any node can serve any request.
- For data: **[[relational-databases|replication]]** (read scaling) and **sharding** (write/storage scaling).

> [!tip] Interview line
> "I'd scale horizontally behind a load balancer and keep the app tier stateless, so I get both scale and availability. The hard part isn't the app tier — it's scaling the **stateful** data layer."

## Related
[[what-is-system-design]] · [[caching]] · [[relational-databases]] · [[nosql-databases]]



# What is Capacity Estimation?

> [!abstract] TL;DR
> Back-of-the-envelope math to size a system: **QPS, storage, bandwidth, memory**. It grounds your design in numbers so you scale the right component.

## What you estimate
1. **QPS** (queries/sec) — read QPS and write QPS separately; reads usually dominate.
2. **Storage** — bytes/record × records/day × retention.
3. **Bandwidth** — QPS × payload size.
4. **Memory** — working set you'd want to [[caching|cache]] (often the hot 20%).

## Numbers worth memorizing
| Quantity | Value |
|---|---|
| Seconds/day | ~86,400 ≈ **10⁵** |
| 1 char | 1 byte |
| KB / MB / GB / TB | 10³ / 10⁶ / 10⁹ / 10¹² bytes |
| Daily → per-second | ÷ ~100,000 |

### Latency ladder (Jeff Dean, rounded)
- Memory read: ~100 ns
- SSD read: ~100 µs (1,000× memory)
- Network round trip (same DC): ~500 µs
- Disk seek (HDD): ~10 ms
- Cross-continent round trip: ~150 ms

## Worked example — 100M DAU, 10 posts read each
- Reads/day = 100M × 10 = 10⁹ → **QPS ≈ 10⁹ / 10⁵ = 10,000 read QPS**
- Peak ≈ 2–3× average → plan for ~25k QPS
- If each post ≈ 1 KB → bandwidth ≈ 10k × 1 KB = **10 MB/s**

## Why it matters
The estimate tells you *what to scale*: high read QPS → [[caching]] + read replicas; high storage → sharding; high write QPS → [[nosql-databases|write-optimized store]] / queue.

> [!tip] Interview habit
> Round aggressively, state assumptions, and separate **read vs write**. Interviewers grade reasoning, not arithmetic precision.

## Related
[[what-is-system-design]] · [[caching]] · [[horizontal-vs-vertical-scaling]]



# What is HTTP?

> [!abstract] TL;DR
> HTTP is a **stateless, request–response** application-layer protocol (over [[tcp-ip-stack|TCP]]) that clients use to fetch and mutate resources on servers.

## Key properties
- **Request/response** — client sends a request, server returns a response.
- **Stateless** — each request is independent; state is carried via cookies, tokens, or server-side sessions.
- **Text-based** (HTTP/1.1) methods + headers + body.

## Anatomy
**Request:** method + path + headers + optional body
**Response:** status code + headers + optional body

### Common methods
| Method | Purpose | Safe/Idempotent |
|---|---|---|
| GET | Read | safe, idempotent |
| POST | Create / action | neither |
| PUT | Replace | idempotent |
| PATCH | Partial update | not guaranteed |
| DELETE | Remove | idempotent |

### Status code families
- **2xx** success (200 OK, 201 Created)
- **3xx** redirect (301 permanent, 302 temporary, 304 Not Modified)
- **4xx** client error (400, 401 unauth, 403 forbidden, 404, 429 too many requests)
- **5xx** server error (500, 502, 503, 504)

## Versions
- **HTTP/1.1** — one request at a time per connection (head-of-line blocking); keep-alive reuses connections.
- **HTTP/2** — multiplexing over one connection, header compression.
- **HTTP/3** — runs over **QUIC (UDP)**, removes TCP head-of-line blocking.

## HTTPS
HTTP + **TLS** encryption. TLS handshake negotiates keys so traffic is confidential and tamper-evident. Assume HTTPS everywhere.

## Related
[[tcp-ip-stack]] · [[what-happens-when-you-visit-google]] · [[what-is-system-design]]



# What is the Internet TCP/IP Stack?

> [!abstract] TL;DR
> A layered model where each layer adds a job: **Link → Internet (IP) → Transport (TCP/UDP) → Application (HTTP)**. Each layer wraps the one above with its own header.

## The 4 layers (TCP/IP model)
| Layer | Job | Examples |
|---|---|---|
| **Application** | App semantics | [[http\|HTTP]], DNS, SMTP |
| **Transport** | Process-to-process delivery | TCP, UDP |
| **Internet** | Host-to-host routing | IP, ICMP |
| **Link** | Physical/local delivery | Ethernet, Wi-Fi, ARP |

## TCP vs UDP
| | TCP | UDP |
|---|---|---|
| Connection | Yes (handshake) | No |
| Reliability | Ordered, retransmits lost packets | Best-effort, may drop |
| Speed/overhead | Higher overhead | Low overhead |
| Use | Web, APIs, files | Video, games, DNS, QUIC |

## TCP 3-way handshake
`SYN → SYN-ACK → ACK` establishes a connection before data flows. Adds a round trip of latency — one reason connection reuse ([[http|keep-alive]], HTTP/2) matters.

## Encapsulation
Data gets wrapped top-down as it goes out and unwrapped bottom-up as it arrives:
`[Ethernet [ IP [ TCP [ HTTP payload ] ] ] ]`

## Why it matters for system design
Latency = handshakes + round trips + distance. Fewer round trips (connection pooling, CDNs closer to users, HTTP/2/3) = faster systems.

## Related
[[http]] · [[what-happens-when-you-visit-google]]



# What Happens When You Enter Google.com?

> [!abstract] TL;DR
> The classic end-to-end question. It stitches together **DNS → TCP → TLS → HTTP → render**, and tests whether you understand the whole stack.

## The full path
1. **URL parse** — browser splits scheme (`https`), host (`google.com`), path.
2. **Cache checks** — browser cache → OS cache → check if already resolved.
3. **DNS resolution** — hostname → IP. Recursive resolver asks root → TLD (`.com`) → authoritative nameserver. Cached along the way with TTLs.
4. **[[tcp-ip-stack|TCP handshake]]** — 3-way `SYN/SYN-ACK/ACK` to the server IP (port 443).
5. **TLS handshake** — negotiate keys; server presents certificate; secure channel established.
6. **[[http|HTTP request]]** — `GET /` with headers (cookies, user-agent).
7. **Server-side** — likely hits a **load balancer** → app server → maybe a [[caching|cache]]/[[relational-databases|DB]] → returns HTML.
8. **Response** — status + HTML; often a **[[caching|CDN]]** serves static assets from a nearby edge.
9. **Render** — browser parses HTML, builds DOM, fetches CSS/JS/images (more requests), paints the page.

## What each step reveals
| Step | Concept tested |
|---|---|
| DNS | Caching, hierarchy, TTLs |
| TCP/TLS | Round trips, latency |
| Load balancer | [[horizontal-vs-vertical-scaling\|Horizontal scaling]] |
| CDN/cache | Latency reduction |
| DB | Data layer |

> [!tip] Interview strategy
> Narrate the path and pause at each hop to mention the **scaling/latency** lesson. This one question lets you demonstrate the entire stack.

## Related
[[http]] · [[tcp-ip-stack]] · [[caching]] · [[horizontal-vs-vertical-scaling]]



# What are Relational Databases?

> [!abstract] TL;DR
> Databases that store data in **tables (rows/columns)** with enforced **schema** and relationships, queried with **SQL**, and give **ACID** guarantees. Default choice when data is structured and correctness matters.

## Core ideas
- **Tables** with a fixed **schema**; rows = records, columns = fields.
- **Keys** — primary key (unique row id), foreign key (link to another table).
- **Normalization** — remove redundancy by splitting into related tables; join at query time.
- **SQL** — declarative queries (`SELECT ... JOIN ... WHERE`).

## ACID (the reason to pick SQL)
| Property | Meaning |
|---|---|
| **Atomicity** | All-or-nothing transactions |
| **Consistency** | Constraints always hold |
| **Isolation** | Concurrent txns don't corrupt each other |
| **Durability** | Committed data survives crashes |

## Strengths vs limits
- ✅ Strong consistency, complex queries/joins, mature tooling.
- ⚠️ Vertical scaling ceiling; **horizontal scaling of writes is hard** (sharding adds complexity, joins across shards are painful).

## Scaling a relational DB
1. **[[database-indexes|Indexes]]** — speed up reads.
2. **Read replicas** — copy for read scaling (async → eventual consistency on replicas).
3. **[[caching|Caching]]** — offload hot reads.
4. **Sharding** — partition by key across nodes (last resort; complex).

## When to choose
Structured data, transactions, correctness (payments, orders, users). Otherwise consider [[nosql-databases|NoSQL]].

## Related
[[database-indexes]] · [[nosql-databases]] · [[caching]] · [[horizontal-vs-vertical-scaling]]



# What are Database Indexes?

> [!abstract] TL;DR
> An index is an auxiliary data structure (usually a **B-tree**) that lets the DB find rows without scanning the whole table — trading **extra storage + slower writes** for **much faster reads**.

## The problem it solves
Without an index, `WHERE email = ?` does a **full table scan** — O(n). An index turns that into ~O(log n) lookups.

## How it works
- Most indexes are **B+ trees**: sorted, balanced, great for equality **and range** queries (`BETWEEN`, `ORDER BY`).
- **Hash indexes**: O(1) equality lookups, but no range queries.
- The index stores the indexed column(s) + a pointer to the row.

## The trade-off
| Gain | Cost |
|---|---|
| Faster reads/lookups | Extra disk storage |
| Faster sorts/ranges | **Slower writes** (every insert/update maintains the index) |
| | Can be unused if query doesn't match index |

## Key concepts
- **Primary index** — on the primary key (often clustered = table stored in key order).
- **Secondary index** — on other columns.
- **Composite index** — multiple columns; **order matters** (leftmost-prefix rule).
- **Covering index** — includes all columns a query needs, so the DB never touches the table.

> [!warning] Don't over-index
> Every index slows writes and costs storage. Index the columns you actually filter/sort/join on — not everything.

## Interview line
"Indexes make reads fast and writes slower. I'd index high-selectivity columns used in WHERE/JOIN/ORDER BY, and watch write-heavy tables for index bloat."

## Related
[[relational-databases]] · [[caching]] · [[capacity-estimation]]



# What are NoSQL Databases?

> [!abstract] TL;DR
> Non-relational stores that trade rigid schema + joins for **horizontal scalability, flexible data models, and high write throughput**. Usually favor **availability + partition tolerance** over strict consistency.

## Four main types
| Type | Model | Examples | Good for |
|---|---|---|---|
| **Key-value** | key → blob | Redis, DynamoDB | [[caching]], sessions |
| **Document** | JSON-like docs | MongoDB, Couchbase | flexible/evolving schema |
| **Wide-column** | rows w/ dynamic columns | Cassandra, HBase | huge write volume, time-series |
| **Graph** | nodes + edges | Neo4j | relationships, social graphs |

## Why NoSQL scales
- **Denormalized** — data duplicated so a read hits one place (no joins).
- **Partition-friendly** — designed to shard across many nodes from day one.
- Often **eventually consistent** — replicas converge over time.

## SQL vs NoSQL
| | SQL | NoSQL |
|---|---|---|
| Schema | Fixed | Flexible |
| Scaling | Vertical / hard sharding | Horizontal by design |
| Joins/txns | Strong | Limited |
| Consistency | Strong (ACID) | Often eventual (BASE) |
| Best when | Structured + correctness | Scale + flexible/huge data |

## CAP intuition
During a network **P**artition you must choose: **C**onsistency (reject/wait) or **A**vailability (serve possibly-stale data). Many NoSQL stores pick **AP**.

> [!tip] Interview stance
> Not "NoSQL is better" — pick by access pattern. "Structured + transactional → SQL. Massive scale, flexible schema, or key-value access → NoSQL." Polyglot persistence (both) is common.

## Related
[[relational-databases]] · [[caching]] · [[what-is-system-design]]



# What is a Cache?

> [!abstract] TL;DR
> A cache stores copies of frequently-accessed data in a **faster/closer** layer so most requests skip the slow source. It's the #1 lever for reducing latency and DB load.
> (This is the *distributed-systems* cache. For the CPU/hardware version see the `Cache Memory` note — same principle, different layer.)

## Why cache
- Cut **latency** (serve from memory, not disk/DB).
- Reduce **load** on the [[relational-databases|database]] / downstream services.
- Absorb read spikes cheaply.

Same foundation as hardware caching: **locality of reference** — a small hot subset is accessed repeatedly.

## Where caches live (layers)
| Layer | Example |
|---|---|
| Client/browser | HTTP cache headers |
| CDN (edge) | Cloudflare, CloudFront — static assets near users |
| Application | Redis, Memcached — hot queries/objects |
| Database | query/buffer cache |

## Caching strategies
| Strategy | How | Note |
|---|---|---|
| **Cache-aside** (lazy) | App checks cache; on miss, load DB + populate | Most common |
| **Read-through** | Cache loads from DB itself on miss | Cache library owns it |
| **Write-through** | Write to cache **and** DB together | Consistent, slower writes |
| **Write-back** | Write to cache, flush to DB later | Fast, risk of loss |

## Eviction policies
When full, decide what to drop: **LRU** (least recently used, most common), **LFU** (least frequently used), **FIFO**, **TTL** expiry.

## The hard parts
- **Invalidation** — "one of the two hard things in CS." Stale data if the source changes and the cache doesn't.
- **Cache stampede** — many misses hammer the DB at once (mitigate: locks, request coalescing, staggered TTLs).
- **Hit ratio** = hits / (hits + misses). Higher = better; low hit ratio means the cache isn't earning its keep.

## Related
[[relational-databases]] · [[what-happens-when-you-visit-google]] · [[horizontal-vs-vertical-scaling]] · [[capacity-estimation]]



# What is Thrashing?

> [!abstract] TL;DR
> Thrashing is when a system spends more time **swapping pages between RAM and disk** than doing useful work — throughput collapses because the working set doesn't fit in memory.

## The mechanism
- Programs need their **working set** (actively used pages) in RAM.
- If too many processes compete for too little RAM, pages are constantly **evicted then immediately needed again** → page faults → disk I/O.
- Disk is ~10⁵× slower than RAM, so the CPU stalls waiting; utilization *looks* high but real work drops toward zero.

## Signs
- Very high page-fault / swap rate.
- CPU busy but throughput plummets.
- Adding more concurrent work makes it **worse**, not better.

## Causes
- Working set > available RAM.
- Over-subscribing memory (too many processes / too-large degree of multiprogramming).

## Fixes
- Reduce degree of multiprogramming (fewer concurrent processes).
- Add RAM / right-size instances.
- **Working-set model** and **page-fault-frequency** control by the OS.
- Better locality so the hot set fits in memory.

## Why it's in system-design prep
It's the same idea as a **[[caching|cache]] with a hit ratio too low to help** — when the fast layer can't hold the working set, you pay the slow-path cost on nearly every access. Applies to RAM↔disk, cache↔DB, CDN↔origin.

## Related
[[caching]] · [[threads]] · [[capacity-estimation]]



# What are Threads?

> [!abstract] TL;DR
> A thread is the smallest unit of execution. Multiple threads live **inside one process**, sharing its memory but running (potentially) in parallel — the basis of concurrency.

## Process vs Thread
| | Process | Thread |
|---|---|---|
| Memory | Own isolated address space | Shares process memory |
| Creation cost | Heavy | Light |
| Communication | IPC (slow, explicit) | Shared memory (fast) |
| Failure blast radius | Isolated | One crash can take the process down |

## Why threads
- **Concurrency** — handle many requests/tasks at once (e.g. a web server per-request).
- **Parallelism** — use multiple CPU cores for CPU-bound work.
- **Responsiveness** — do I/O without blocking the whole program.

## Concurrency ≠ Parallelism
- **Concurrency** — dealing with many things at once (interleaving); possible on one core.
- **Parallelism** — doing many things at the exact same instant; needs multiple cores.

## The dangers (shared state)
- **Race condition** — result depends on timing of unsynchronized access.
- **Deadlock** — threads wait on each other's locks forever.
- Fixes: **mutexes/locks**, atomics, avoid shared mutable state, message passing.

## Threads vs async I/O
For I/O-bound work (waiting on network/DB), an **event loop / async** model (or thread pool) scales better than one thread per connection, which is memory-heavy and can lead to [[thrashing]] under load. CPU-bound work wants real threads/processes across cores.

## Related
[[thrashing]] · [[caching]] · [[what-is-system-design]]



---

# Load Balancing


# What is Load Balancing?

> [!abstract] TL;DR
> A load balancer (LB) sits in front of your servers and spreads incoming requests across them, so no single server is overwhelmed. It's the enabler of [[horizontal-vs-vertical-scaling|horizontal scaling]] and high availability.

## Why
- **Distribute load** evenly → higher throughput.
- **High availability** → route around dead/unhealthy nodes (via health checks).
- **Scalability** → add/remove servers behind the LB transparently.

## Where it sits
`Client → DNS → Load Balancer → [Server 1 · Server 2 · Server N]`
Can operate at **L4** (transport — routes by IP/port, fast) or **L7** (application — routes by URL/headers/cookies, smarter).

## Common algorithms
| Algorithm | Idea |
|---|---|
| **Round robin** | Rotate through servers in order |
| **Weighted round robin** | Bigger servers get more traffic |
| **Least connections** | Send to the least-busy server |
| **Least response time** | Fastest-responding server |
| **IP hash / [[consistent-hashing]]** | Same client → same server (sticky) |

## Key concepts
- **Health checks** — LB pings servers; stops routing to unhealthy ones.
- **Sticky sessions** — pin a user to one server (needed if state is local; avoid by keeping servers [[threads|stateless]]).
- **Redundancy** — the LB itself must not be a [[single-point-of-failure]]; run active-passive/active-active LBs.

## Related
[[horizontal-vs-vertical-scaling]] · [[consistent-hashing]] · [[sharding]] · [[single-point-of-failure]]

---
Source: [takeUforward roadmap](https://youtu.be/K0Ta65OqQkY)



# What is Consistent Hashing?

> [!abstract] TL;DR
> A hashing scheme that maps both **keys and servers onto a ring**, so adding/removing a server only remaps a small fraction of keys — not all of them. The backbone of [[sharding]] and distributed [[caching]].

## The problem it solves
Naive sharding uses `server = hash(key) % N`. If **N changes** (add/remove a node), *almost every* key remaps → massive data movement and cache misses.

## How it works
1. Hash servers onto a circular ring (0 … 2³²).
2. Hash each key onto the same ring.
3. A key belongs to the **first server clockwise** from it.
4. Add/remove a node → only the keys between it and its neighbor move (~1/N of keys).

## Virtual nodes
One physical server is placed at **many** points on the ring (virtual nodes) so load is even and removing a node spreads its keys across many others, not just one.

## Where it's used
- Distributed caches (Memcached clients), [[nosql-databases|Cassandra]]/DynamoDB partitioning
- [[load-balancing|Load balancers]] wanting sticky routing
- Any system that must scale nodes without reshuffling everything

## Remember
Modulo hashing = remap everything on change. Consistent hashing = remap ~1/N. That's the whole point.

## Related
[[sharding]] · [[load-balancing]] · [[distributed-caching]] · [[data-replication]]

---
Source: [takeUforward roadmap](https://youtu.be/zaRkONvyGr8)



# What is Sharding?

> [!abstract] TL;DR
> Splitting one large dataset **horizontally** across multiple machines (shards), each holding a subset of rows. It's how you scale **writes and storage** past a single machine.

## Partitioning vs replication
- **Sharding (partitioning)** — different data on different nodes (scales capacity/writes).
- **[[data-replication|Replication]]** — same data copied to many nodes (scales reads + availability).
- Real systems do **both**: each shard is also replicated.

## Sharding strategies
| Strategy | How | Watch out |
|---|---|---|
| **Range-based** | Partition by key ranges (A–M, N–Z) | Hotspots if data skewed |
| **Hash-based** | `shard = hash(key) % N` | Rebalancing is costly → use [[consistent-hashing]] |
| **Directory-based** | Lookup table maps key → shard | Lookup service can become bottleneck/SPOF |
| **Geo-based** | Partition by region | Good for locality/latency |

## The hard parts
- **Cross-shard queries / joins** — slow, need scatter-gather.
- **Rebalancing** — moving data when adding shards ([[consistent-hashing]] minimizes this).
- **Hotspots** — a "celebrity" key overloading one shard; pick a good **shard key**.
- **Transactions across shards** — need distributed transactions (hard).

## Remember
Choose a shard key with **high cardinality + even access**. A bad shard key is the #1 cause of hotspots.

## Related
[[consistent-hashing]] · [[data-replication]] · [[relational-databases]] · [[nosql-databases]]

---
Source: [takeUforward roadmap](https://youtu.be/5faMjKuB9bc)



---

# DataStores


# What are Bloom Filters?

> [!abstract] TL;DR
> A space-efficient **probabilistic** data structure that answers "is this item *definitely not* in the set, or *possibly* in it?" No false negatives, some false positives. Used to avoid expensive lookups.

## How it works
- A bit array + **k hash functions**.
- **Insert:** hash the item k ways, set those k bits to 1.
- **Query:** hash k ways; if *any* bit is 0 → **definitely not present**. If all 1 → **probably present** (could be a false positive).

## Guarantees
| Answer | Meaning |
|---|---|
| "Not in set" | 100% correct (no false negatives) |
| "In set" | Probably — small false-positive chance |

Can't delete items (a bit may be shared) — use a **counting Bloom filter** if you must.

## Why it matters
Skip costly disk/network lookups: check the cheap in-memory filter first.
- **[[nosql-databases|Cassandra/HBase]]** — avoid reading SSTables that don't contain the key.
- **[[caching|Caches/CDNs]]** — "one-hit-wonder" filtering.
- Databases, spell-checkers, malicious-URL checks.

## Trade-off
Tiny memory + O(k) lookups **vs** a tunable false-positive rate (more bits / more hashes → fewer false positives).

## Related
[[nosql-databases]] · [[nosql-optimization]] · [[caching]]

---
Source: [takeUforward roadmap](https://youtu.be/bgzUdBVr5tE)



# What is Data Replication?

> [!abstract] TL;DR
> Keeping **copies of the same data on multiple nodes** for higher availability, read scaling, and durability. The core tension is *how* copies stay in sync ([[data-consistency|consistency]] vs latency).

## Why replicate
- **Availability** — survive node failure (failover to a replica).
- **Read scaling** — spread reads across replicas.
- **Latency** — put copies near users (geo-replication).
- **Durability** — data survives if one disk dies.

## Replication models
| Model | How | Trade-off |
|---|---|---|
| **Single-leader** (primary-replica) | Writes to leader, replicated to followers | Simple; leader is write bottleneck/SPOF |
| **Multi-leader** | Multiple nodes accept writes | Write availability; conflict resolution needed |
| **Leaderless** (Dynamo/Cassandra) | Any node writes; quorum reads/writes | Highly available; tunable consistency |

## Sync vs async
- **Synchronous** — wait for replicas to ack → strong consistency, higher latency, less available.
- **Asynchronous** — ack immediately, replicate in background → fast + available, but replicas lag (**replication lag** → stale reads).

## Quorum (leaderless)
With N replicas, if **W + R > N**, reads and writes overlap → you read the latest write. Tune W/R for consistency vs latency.

## Related
[[sharding]] · [[data-consistency]] · [[tradeoff-consistency-vs-availability]] · [[single-point-of-failure]]

---
Source: [takeUforward roadmap](https://youtu.be/GeGxgmPTe4c)



# How are NoSQL Databases Optimized?

> [!abstract] TL;DR
> Many NoSQL stores are **write-optimized** using an **LSM-tree** (Log-Structured Merge tree) instead of the B-tree that SQL databases use. This makes writes sequential and fast.

## B-tree vs LSM-tree
| | B-tree (SQL) | LSM-tree (many NoSQL) |
|---|---|---|
| Writes | In-place, random I/O | Append to in-memory table, sequential |
| Reads | Fast, direct | May check several levels |
| Best for | Read-heavy, range queries | **Write-heavy** workloads |

## LSM-tree write path
1. Write goes to an in-memory **memtable** (+ a **WAL** for durability).
2. When full, memtable is flushed to disk as an immutable **SSTable** (sorted).
3. Background **compaction** merges SSTables, drops deleted/old versions.

## Read-side optimizations
- **[[bloom-filters|Bloom filters]]** — skip SSTables that can't contain the key.
- **Sparse indexes** — jump near the key within an SSTable.
- Sorted SSTables → efficient range scans.

## Other NoSQL optimizations
- **Denormalization** — store data the way it's read (no joins).
- **Partitioning** ([[sharding]]) + **[[data-replication|replication]]** built in.
- **Tunable consistency** (quorums) for latency wins.

## Related
[[nosql-databases]] · [[bloom-filters]] · [[database-indexes]] · [[sharding]]

---
Source: [takeUforward roadmap](https://youtu.be/_5vrfuwhvlQ)



# What are Location-based Databases?

> [!abstract] TL;DR
> Databases/indexes optimized for **spatial queries** — "find things near me," "what's in this region." They map 2D coordinates to a form that ordinary indexes can search efficiently.

## The problem
A normal [[database-indexes|B-tree index]] handles one dimension well, but "nearest neighbors" on (lat, lng) is 2D — a naive scan is O(n). Spatial structures fix this.

## Core techniques
| Technique | Idea | Used by |
|---|---|---|
| **Geohash** | Encode lat/lng into a string; shared prefix = nearby | Redis, Elasticsearch |
| **Quadtree** | Recursively split space into 4 quadrants | maps, spatial search |
| **R-tree** | Bounding-box hierarchy | PostGIS |
| **S2 / H3** | Sphere cells / hexagonal grid | Google S2, Uber H3 |

## Why geohash is popular
Turns 2D proximity into a **1D sortable prefix**, so you can use a normal index/[[sharding|shard]] key. Nearby points share prefixes → range scan finds neighbors. (Edge case: points across a cell boundary — query neighboring cells too.)

## Where used
Ride-hailing (Uber/Lyft driver matching), food delivery, "restaurants near me," geofencing, proximity notifications.

## Related
[[database-indexes]] · [[sharding]] · [[nosql-databases]]

---
Source: [takeUforward roadmap](https://youtu.be/OcUKFIjhKu0)



# Database Migrations

> [!abstract] TL;DR
> Safely evolving a database's **schema or data** (or moving to a new store) **while the system stays live** — without downtime or data loss. It's an operational discipline, not a one-shot script.

## Two meanings
1. **Schema migration** — add/change columns, indexes, tables.
2. **Data migration** — move data to a new database/engine (e.g. SQL → NoSQL, or resharding).

## The golden rule: backward compatibility
Old and new code run **at the same time** during a rollout, so every migration step must work with both. Never make a breaking change in one step.

## Expand–contract (parallel change) pattern
1. **Expand** — add the new column/table (nullable, non-breaking).
2. **Migrate + dual-write** — write to both old and new; backfill old data in batches.
3. **Read from new** — switch reads once new is complete and verified.
4. **Contract** — stop writing old; drop it after a safety window.

## Zero-downtime data-store move
Dual-write → backfill → shadow-read & compare → cut over → decommission. Keep a **rollback** path at every step.

## Watch out for
- **Locking** big tables (long `ALTER` blocks writes) — use online schema-change tools.
- **Backfills** hammering the DB — batch + throttle.
- **Irreversible steps** — always have a rollback.

## Related
[[relational-databases]] · [[nosql-databases]] · [[sharding]] · [[data-replication]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/database-migrations/database-migrations)



---

# Consistency vs. Availability


# What is Data Consistency?

> [!abstract] TL;DR
> Consistency = whether all readers see the **same, latest** value after a write. In distributed systems you trade consistency against **latency and availability** (CAP/PACELC).

## The spectrum (strong → weak)
| Model | Guarantee |
|---|---|
| **Strong / linearizable** | Every read sees the most recent write, always |
| **Sequential** | Everyone sees ops in the same order |
| **Causal** | Cause-before-effect order preserved |
| **Eventual** | Replicas converge *eventually* if writes stop |

## CAP theorem
During a network **P**artition, you must choose:
- **CP** — stay consistent, sacrifice availability (reject/wait).
- **AP** — stay available, serve possibly-stale data.
No partition → you can have both.

## PACELC (the fuller picture)
If **P**artition → choose **A** or **C**; **E**lse (normal ops) → choose **L**atency or **C**onsistency. Even without failures, strong consistency costs latency.

## Practical note
Strong consistency needs coordination (quorums/consensus) → slower. Many systems pick **eventual/causal** consistency for speed and add app-level fixes (read-your-writes, version vectors).

## Related
[[data-consistency-levels]] · [[transaction-isolation-levels]] · [[data-replication]] · [[tradeoff-consistency-vs-availability]]

---
Source: [takeUforward roadmap](https://youtu.be/m4q7VkgDWrM)



# Data Consistency Levels

> [!abstract] TL;DR
> Beyond "strong vs eventual," there are **client-centric consistency guarantees** that define what a *single client* can rely on across a replicated system. You pick the weakest level that still satisfies the product.

## Client-centric guarantees
| Level | Promise |
|---|---|
| **Read-your-writes** | You always see your own latest write |
| **Monotonic reads** | Once you've seen a value, you won't see an older one |
| **Monotonic writes** | Your writes apply in the order you made them |
| **Writes-follow-reads** | A write is ordered after any write you'd read |

## Why levels matter
Full strong consistency is expensive. These levels give **"good enough" guarantees cheaply** for the parts that matter (e.g. a user must see their own comment → read-your-writes), while everything else stays eventually consistent.

## Tunable consistency (quorum)
Leaderless stores (Cassandra/Dynamo) let you set per-query levels: `ONE`, `QUORUM`, `ALL`. With **W + R > N**, you get strong-ish consistency; lower values trade consistency for latency/availability.

## Interview framing
"I'd default to eventual consistency for scale, but enforce **read-your-writes** on the user's own data so the UX never looks broken."

## Related
[[data-consistency]] · [[transaction-isolation-levels]] · [[data-replication]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/consistency-in-distributed-systems/what-is-data-consistency)



# Transaction Isolation Levels

> [!abstract] TL;DR
> The **I** in [[relational-databases|ACID]]. Isolation levels define how much concurrent transactions can see each other's uncommitted/changing data. Higher isolation = more correct, less concurrency.

## The read phenomena (anomalies)
| Anomaly | What happens |
|---|---|
| **Dirty read** | Read another txn's *uncommitted* change |
| **Non-repeatable read** | Re-reading a row gives a different value (someone updated it) |
| **Phantom read** | Re-running a query returns new rows (someone inserted) |

## The 4 SQL isolation levels
| Level | Prevents |
|---|---|
| **Read Uncommitted** | (nothing — dirty reads allowed) |
| **Read Committed** | dirty reads |
| **Repeatable Read** | dirty + non-repeatable reads |
| **Serializable** | all of them (as if txns ran one at a time) |

Higher level → fewer anomalies but more locking/aborts → **less throughput**.

## How it's enforced
- **Locking** (pessimistic) — shared/exclusive locks.
- **MVCC** (optimistic) — each txn reads a consistent snapshot (Postgres, MySQL InnoDB).

## Interview note
"Most OLTP systems default to **Read Committed** or **Repeatable Read**. Use **Serializable** only where correctness is critical (e.g. money) because it serializes and hurts throughput ([[tradeoff-throughput-vs-latency]])."

## Related
[[relational-databases]] · [[data-consistency]] · [[threads]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/consistency-in-distributed-systems/Transaction-Isolation-Levels-Read-Uncommitted-Data)



---

# Message Queues


# What is a Message Queue?

> [!abstract] TL;DR
> A buffer that lets services communicate **asynchronously**: a producer drops a message, a consumer picks it up later. It **decouples** services, absorbs spikes, and improves resilience.

## Why use one
- **Decoupling** — producer & consumer don't need to be up at the same time.
- **Buffering / load leveling** — absorb traffic spikes; consumers work at their own pace.
- **Resilience** — if a consumer dies, messages wait; retry later.
- **Async work** — return to the user fast; do slow work (email, video encode) in background.

## Core concepts
- **Producer / Consumer**, **Broker** (Kafka, RabbitMQ, SQS).
- **Ack** — consumer confirms processing; unacked messages get redelivered.
- **Delivery semantics:** at-most-once, **at-least-once** (common; requires **idempotent** consumers), exactly-once (hard/expensive).
- **DLQ (dead-letter queue)** — messages that repeatedly fail land here.
- **Ordering** — global order is hard; usually ordered *per partition/key*.

## Queue vs Log
- **Queue (RabbitMQ/SQS)** — message removed once consumed.
- **Log (Kafka)** — messages retained; consumers track their own offset; multiple consumers can replay.

## Interview note
Reach for a queue whenever work can be done **later** or a spike must be **smoothed**. Design consumers to be **idempotent** (at-least-once means duplicates happen).

## Related
[[publisher-subscriber-model]] · [[event-driven-systems]] · [[database-as-message-queue]] · [[asynchronous-apis]]

---
Source: [takeUforward roadmap](https://youtu.be/oUJbuFMyBDk)



# What is the Publisher–Subscriber Model?

> [!abstract] TL;DR
> A messaging pattern where publishers send messages to **topics**, and **all** subscribers to that topic receive a copy. One-to-many broadcast, fully decoupled — publishers don't know who's listening.

## Pub/Sub vs plain queue
| | Message Queue (point-to-point) | Pub/Sub (fan-out) |
|---|---|---|
| Delivery | One consumer gets each message | **Every** subscriber gets a copy |
| Relationship | 1 → 1 (competing consumers) | 1 → many |
| Example | Task/work queue | Event broadcast, notifications |

## How it works
`Publisher → Topic → [Subscriber A · Subscriber B · Subscriber C]`
The **broker** (Kafka, Google Pub/Sub, Redis Pub/Sub, SNS) routes by topic. Publishers and subscribers never reference each other → maximum decoupling.

## Push vs pull
- **Push** — broker delivers to subscribers.
- **Pull** — subscribers poll for messages (Kafka consumers). See [[tradeoff-pull-vs-push]].

## Where used
Fan-out notifications, cache invalidation broadcasts, [[event-driven-systems|event-driven]] microservices, activity feeds, real-time updates.

## Trade-offs
- ✅ Add new subscribers without touching publishers.
- ⚠️ Harder to trace flow; must handle slow/failed subscribers, duplicates, ordering.

## Related
[[message-queues]] · [[event-driven-systems]] · [[tradeoff-pull-vs-push]]

---
Source: [takeUforward roadmap](https://youtu.be/FMhbR_kQeHw)



# What are Event-Driven Systems?

> [!abstract] TL;DR
> Architecture where services react to **events** ("something happened") rather than calling each other directly. Services emit events; interested services respond. Loose coupling at the system level.

## Request-driven vs event-driven
- **Request-driven** — Service A calls Service B and waits (synchronous, tight coupling).
- **Event-driven** — Service A emits `OrderPlaced`; B, C, D react independently (async, loose coupling).

## Key patterns
| Pattern | Idea |
|---|---|
| **[[publisher-subscriber-model|Pub/Sub]]** | Broadcast events to many consumers |
| **Event sourcing** | Store the *sequence of events* as source of truth; rebuild state by replay |
| **CQRS** | Separate write model (commands) from read model (queries) |
| **Saga** | Coordinate a multi-service transaction via events + compensating actions |

## Benefits
- Decoupling, independent scaling, easy to add new reactions.
- Natural audit log (event history).
- Resilience — consumers catch up after downtime.

## Challenges
- **Eventual consistency** ([[data-consistency]]) — state converges, not instant.
- Harder debugging/tracing (needs good [[anomaly-detection|observability]]).
- **Idempotency** & duplicate handling required.
- Event schema evolution.

## Related
[[message-queues]] · [[publisher-subscriber-model]] · [[microservices-vs-monoliths]] · [[data-consistency]]

---
Source: [takeUforward roadmap](https://youtu.be/rJHTK2TfZ1I)



# Database as a Message Queue

> [!abstract] TL;DR
> You can use a regular database table as a simple queue (rows = messages, a status column tracks progress). Fine at small scale, but it doesn't replace a real broker as load grows.

## How it works
- Insert a row per job with `status = pending`.
- Workers poll: `SELECT ... WHERE status='pending' ... FOR UPDATE SKIP LOCKED` → mark `processing` → do work → `done`.
- `SKIP LOCKED` lets multiple workers grab different rows without blocking.

## Why do it
- **Transactional consistency** — enqueue the job in the *same transaction* as your data write (solves the dual-write problem). This is the basis of the **Transactional Outbox** pattern.
- No extra infrastructure to run.

## Limits (why real brokers exist)
- **Polling** wastes DB resources; adds latency vs push.
- The DB becomes a **bottleneck / [[single-point-of-failure]]** under high throughput.
- No native pub/sub fan-out, partitioning, or replay like [[message-queues|Kafka]].

## Transactional Outbox pattern
Write business data + an `outbox` event row in one transaction; a separate relay publishes outbox rows to the real broker. Guarantees "event emitted iff data committed."

## Interview note
"For low volume or to guarantee atomic enqueue-with-write, a DB-backed queue (outbox) is great. At scale, move to a dedicated broker."

## Related
[[message-queues]] · [[event-driven-systems]] · [[relational-databases]] · [[database-migrations]]

---
Source: [takeUforward roadmap](https://youtu.be/9T-gNZ5bGCw)



---

# DevOps Concepts


# What is a Single Point of Failure?

> [!abstract] TL;DR
> A SPOF is any component whose failure takes down the **whole system**. High-availability design is largely the practice of hunting down and eliminating SPOFs through **redundancy**.

## Common SPOFs
- A single [[load-balancing|load balancer]], database primary, cache, or message broker.
- A single availability zone / data center.
- A single DNS provider or third-party dependency.

## How to remove them
| Technique | Effect |
|---|---|
| **Redundancy** | N+1 copies of every critical component |
| **[[data-replication|Replication]] + failover** | Promote a replica when the primary dies |
| **Active-active** | Multiple live nodes share load (also scales) |
| **Multi-AZ / multi-region** | Survive a whole zone outage |
| **Health checks** | Detect failure and route around it |

## Availability math
Availability is measured in **nines**: 99.9% ≈ 8.7h down/yr, 99.99% ≈ 52 min/yr.
- **Series** (A depends on B): multiply → availability *drops*.
- **Parallel** (redundant): failure only if *all* fail → availability *rises*.

## Interview habit
When you draw a design, point at each box and ask **"what if this dies?"** Then add redundancy + failover. Don't forget the LB and the DB primary.

## Related
[[cascading-failures]] · [[data-replication]] · [[load-balancing]] · [[service-discovery-heartbeats]]

---
Source: [takeUforward roadmap](https://youtu.be/-BOysyYErLY)



# What are Containers?

> [!abstract] TL;DR
> A container packages an app **with all its dependencies** into one portable unit that runs the same everywhere. It shares the host OS kernel, making it far lighter than a VM. (Overlaps your DevOps track — Docker.)

## Container vs VM
| | Container | Virtual Machine |
|---|---|---|
| Isolates via | OS kernel (namespaces, cgroups) | Full guest OS + hypervisor |
| Size / startup | MBs / seconds | GBs / minutes |
| Overhead | Low (shares kernel) | High (own OS) |
| Isolation | Process-level | Stronger (full OS) |

## How it works (Linux primitives)
- **Namespaces** — isolate what a process can *see* (PIDs, network, mounts).
- **cgroups** — limit what it can *use* (CPU, memory).
- **Image** — read-only layered filesystem; **container** = running instance of an image.

## Why they matter for system design
- **"Works on my machine" solved** — same artifact dev → prod.
- **Fast, dense scaling** — spin up many instances quickly behind a [[load-balancing|LB]].
- **Foundation for orchestration** — Kubernetes schedules containers, handles health/[[service-discovery-heartbeats|discovery]], self-healing, autoscaling.

## Remember
Container = lightweight, portable, kernel-sharing process box. VM = heavyweight, full-OS isolation.

## Related
[[service-discovery-heartbeats]] · [[microservices-vs-monoliths]] · [[single-point-of-failure]]

---
Source: [takeUforward roadmap](https://www.youtube.com/watch?v=GOuVeZmMee0)



# What is Service Discovery and Heartbeats?

> [!abstract] TL;DR
> In a dynamic system, service instances come and go (autoscaling, crashes, deploys). **Service discovery** lets services find each other's current addresses; **heartbeats** detect which instances are alive.

## The problem
Hardcoding IPs breaks when instances scale up/down or move. You need a live "phone book" of healthy instances.

## Service discovery models
| Model | How |
|---|---|
| **Client-side** | Client queries a **registry** (Consul, etcd, Eureka) and picks an instance |
| **Server-side** | A [[load-balancing|load balancer]]/proxy queries the registry and routes |
| **DNS-based** | Registry updates DNS records |

Flow: instance **registers** on startup → registry tracks it → clients look it up → instance **deregisters** on shutdown.

## Heartbeats
Instances periodically ping the registry ("I'm alive"). Miss N heartbeats → marked **unhealthy** and removed from routing. This is how the system routes around failures and avoids sending traffic to dead nodes.

- **Push heartbeat** — instance reports in.
- **Pull health check** — registry/LB probes the instance (`/health`).

## Where used
Kubernetes (kubelet + liveness/readiness probes), microservice meshes, [[load-balancing|LB]] backends.

## Related
[[single-point-of-failure]] · [[cascading-failures]] · [[containers]] · [[load-balancing]]

---
Source: [takeUforward roadmap](https://youtu.be/lWE_UIbm8NA)



# How to Avoid Cascading Failures?

> [!abstract] TL;DR
> A cascading failure is a chain reaction: one component fails, its load shifts to others, they overload and fail too, until the whole system collapses. Prevention = **isolate, shed, and back off**.

## How the cascade happens
Node dies → its traffic hits the survivors → they slow/overload → retries pile up → more nodes die → total outage. Aggressive client retries make it worse (a **retry storm**).

## Prevention patterns
| Pattern | What it does |
|---|---|
| **Circuit breaker** | Stop calling a failing dependency; fail fast, give it time to recover |
| **Timeouts** | Never wait forever on a slow call |
| **Retries with exponential backoff + jitter** | Retry politely, avoid synchronized retry storms |
| **Bulkheads** | Isolate resources (thread pools) so one dependency can't drain all |
| **Rate limiting / load shedding** | Drop excess load early ([[distributed-rate-limiting]]) |
| **Graceful degradation** | Serve stale [[caching|cache]]/partial results instead of failing |
| **Autoscaling + [[load-balancing]]** | Add capacity, route around dead nodes |

## The three most important
1. **Timeouts** (don't hang), 2. **Circuit breakers** (fail fast), 3. **Backoff + jitter** (no retry storm).

## Interview note
"I'd add timeouts and a circuit breaker on every remote call, retries with jittered backoff, and load shedding so a partial failure degrades gracefully instead of cascading."

## Related
[[single-point-of-failure]] · [[distributed-rate-limiting]] · [[anomaly-detection]] · [[caching]]

---
Source: [takeUforward roadmap](https://www.youtube.com/watch?v=xrizarXJgC8)



# Anomaly Detection in Distributed Systems

> [!abstract] TL;DR
> Automatically spotting when metrics deviate from normal (latency spike, error surge, traffic drop) so you catch problems *before* users do. Built on solid **observability**: metrics, logs, traces.

## The three pillars of observability
| Pillar | Answers |
|---|---|
| **Metrics** | "What is happening?" (numbers over time — QPS, latency, errors) |
| **Logs** | "What exactly happened?" (discrete events) |
| **Traces** | "Where did it happen?" (request path across services) |

## Detection approaches
- **Static thresholds** — alert if error rate > X%. Simple, but noisy/brittle.
- **Statistical** — flag values N standard deviations from the mean; moving averages.
- **Seasonal/ML-based** — learn daily/weekly patterns; flag deviations (traffic is *supposed* to dip at 3am).

## What to watch (the "golden signals")
**Latency, Traffic, Errors, Saturation** (Google SRE). Track **percentiles (p50/p95/p99)**, not just averages — averages hide the tail that hurts users.

## Why it matters
Early detection prevents [[cascading-failures]]; feeds autoscaling and alerting. Tools: Prometheus + Grafana, Datadog (ties to your DevOps track: monitoring-logging).

## Interview note
"I'd expose the four golden signals per service, alert on **p99 latency and error rate**, and use anomaly detection on seasonal metrics to cut false alarms."

## Related
[[cascading-failures]] · [[single-point-of-failure]] · [[distributed-rate-limiting]]

---
Source: [takeUforward roadmap](https://www.youtube.com/watch?v=smiu01pLosI)



# Distributed Rate Limiting

> [!abstract] TL;DR
> Capping how many requests a client can make in a time window — enforced **across many servers** consistently. Protects against abuse, overload, and [[cascading-failures]], and enforces fair usage/quotas.

## Why rate limit
- Prevent abuse / DDoS / scraping.
- Protect backends from overload (load shedding).
- Enforce API plans/quotas and fairness.

## Classic algorithms
| Algorithm | Idea | Note |
|---|---|---|
| **Token bucket** | Tokens refill at rate R; each request spends one | Allows bursts; most common |
| **Leaky bucket** | Requests drain at a fixed rate | Smooths bursts |
| **Fixed window** | Count per fixed interval | Simple; boundary spikes |
| **Sliding window log/counter** | Rolling window | Accurate, more memory |

## The distributed challenge
Limits must be enforced **globally**, but state is spread across many servers/regions.
- **Centralized store** — a shared **[[distributed-caching|Redis]]** counter (atomic `INCR`/Lua). Accurate but adds latency + a dependency.
- **Local + sync** — each node limits locally and periodically reconciles. Faster, approximate.
- Clock skew and the [[data-consistency|consistency]] vs latency trade-off apply.

## Where it lives
Usually at the **[[api-design|API gateway]]** / edge, keyed by API key / user / IP.

## Related
[[cascading-failures]] · [[api-design]] · [[distributed-caching]] · [[tradeoff-consistency-vs-availability]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/distributed-rate-limiting/the_oracle_and_the_timer_wheel)



---

# Caching


# What is Distributed Caching?

> [!abstract] TL;DR
> Spreading a cache across **many nodes** so it can hold more data and serve more traffic than one machine. Think Redis/Memcached cluster in front of your database. Extends the basics in [[caching]].

## Why distribute
A single cache node hits memory and throughput limits and is a [[single-point-of-failure]]. Distributing gives capacity, throughput, and availability.

## How data is placed
- **[[consistent-hashing|Consistent hashing]]** maps keys to nodes so adding/removing a node moves only ~1/N of keys (avoids mass cache misses).
- **[[data-replication|Replication]]** of hot keys for availability and read scaling.

## Deployment patterns
| Pattern | Where cache lives |
|---|---|
| **Client-side / near cache** | In the app process (fast, small) |
| **Distributed cache tier** | Dedicated Redis/Memcached cluster (shared) |
| **Sidecar** | Cache alongside each service |

## Hard problems (at scale)
- **Invalidation & staleness** — keeping copies consistent with the DB.
- **Hot keys** — one popular key overloading a node (mitigate: replicate/split it).
- **Cache stampede** — many misses hit the DB at once (locks, request coalescing, staggered TTLs).
- **Eviction** — see [[cache-replacement-policies]]. **Write path** — see [[cache-write-policies]].

## Related
[[caching]] · [[content-delivery-networks]] · [[consistent-hashing]] · [[cache-write-policies]] · [[cache-replacement-policies]]

---
Source: [takeUforward roadmap](https://youtu.be/U3RkDLtS7uY)



# What are Content Delivery Networks?

> [!abstract] TL;DR
> A CDN is a geographically distributed network of **edge servers** that cache content close to users, cutting latency and offloading your origin. It's caching at the *network edge*.

## Why
- **Lower latency** — content served from a nearby edge, not a distant origin ([[capacity-estimation|distance = round-trip time]]).
- **Offload origin** — edges absorb most requests, protecting your servers.
- **Availability / DDoS absorption** — huge distributed capacity at the edge.

## What it caches
- **Static** — images, CSS, JS, video (classic CDN use).
- **Dynamic/edge** — increasingly, edge compute and cached API responses.

## How content gets to the edge
| Model | How |
|---|---|
| **Pull (lazy)** | Edge fetches from origin on first miss, then caches | 
| **Push** | You upload content to edges ahead of time |

Uses **DNS/anycast** to route each user to the nearest/healthiest edge (a form of geo [[load-balancing]]).

## Cache control
- **TTL** and HTTP headers (`Cache-Control`, `ETag`) decide freshness.
- **Invalidation / purge** when content changes — the hard part (same staleness problem as any [[caching|cache]]).

## Interview note
"Serve all static assets via CDN with long TTLs + versioned URLs (cache-busting), keeping the origin for dynamic requests."

## Related
[[caching]] · [[distributed-caching]] · [[what-happens-when-you-visit-google]] · [[load-balancing]]

---
Source: [takeUforward roadmap](https://www.youtube.com/watch?v=8zX0rue2Hic)



# Cache Write Policies

> [!abstract] TL;DR
> *How* writes flow between the cache and the database. The choice trades **write latency vs consistency vs durability**.

## The policies
| Policy | How a write behaves | Trade-off |
|---|---|---|
| **Write-through** | Write to cache **and** DB synchronously | Consistent + durable; slower writes |
| **Write-back (write-behind)** | Write to cache now, flush to DB later (async/batched) | Fast writes, high throughput; **risk of data loss** if cache dies before flush |
| **Write-around** | Write straight to DB, skip cache | Avoids caching write-only data; first read is a miss |

## Pairing with read strategy
- **Write-through** pairs with **read-through / cache-aside** → cache stays warm and consistent.
- **Write-back** great for **write-heavy** workloads (counters, metrics) where some loss is tolerable.
- **Write-around** good when written data is rarely read soon.

## On a miss (read path recap)
- **Cache-aside (lazy)** — app loads from DB and populates cache. Most common.
- **Read-through** — cache library loads from DB itself.

## Consistency note
Cache + DB is a distributed write → risk of drift. Mitigate with TTLs, write-through, or explicit invalidation. Dual-write ordering bugs are a classic source of staleness.

## Related
[[caching]] · [[cache-replacement-policies]] · [[distributed-caching]] · [[data-consistency]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/caches-deep-dive/write-back-policy)



# Cache Replacement Policies

> [!abstract] TL;DR
> When a cache is full, the **eviction policy** decides which item to drop to make room. The goal: evict things you *won't* need soon, maximizing [[caching|hit ratio]].

## Common policies
| Policy | Evicts | Good when |
|---|---|---|
| **LRU** (Least Recently Used) | Item unused longest | Recency predicts reuse (most common) |
| **LFU** (Least Frequently Used) | Least-accessed item | Popularity is stable |
| **FIFO** | Oldest inserted | Simple; ignores usage |
| **Random** | A random item | Cheap, surprisingly OK |
| **TTL expiry** | Anything past its time-to-live | Freshness matters |

## Smarter variants
- **Segmented LRU (SLRU)** — two segments: probationary + protected. Items promoted to protected on a second hit → resists one-time scans polluting the cache.
- **ARC** — adapts between recency (LRU) and frequency (LFU) automatically.
- **LRU-K / 2Q** — consider the Kth-most-recent access, not just the last.

## The problem each solves
- Plain **LRU** is vulnerable to **scans** (a big one-time sweep evicts your hot set). SLRU/2Q fix this.
- Plain **LFU** can keep stale-but-once-popular items forever → use **aging**/decay.

## Interview note
"Default LRU. If workloads have scans or skewed popularity, SLRU or ARC keeps the hit ratio higher."

## Related
[[caching]] · [[cache-write-policies]] · [[distributed-caching]] · [[thrashing]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/caches-deep-dive/replacement-policies-segmented-lru)



---

# Microservices


# Microservices vs. Monoliths

> [!abstract] TL;DR
> A **monolith** is one deployable app; **microservices** split it into many small, independently deployable services. Microservices buy team/scaling independence at the cost of huge operational complexity.

## Comparison
| | Monolith | Microservices |
|---|---|---|
| Deploy | One unit | Many independent services |
| Scaling | Scale the whole app | Scale hot services only |
| Dev speed (small team) | Fast | Overhead-heavy |
| Coupling | Tight (shared code/DB) | Loose (own DB per service) |
| Failure isolation | One bug can crash all | Contained (with resilience) |
| Complexity | Low | High (network, ops, data) |

## Microservices benefits
- Independent deploy & scale per service.
- Team autonomy; polyglot tech.
- Fault isolation (with [[cascading-failures|circuit breakers]]).

## Microservices costs
- **Distributed systems problems**: network latency, partial failure, [[data-consistency|eventual consistency]].
- **Data**: no cross-service joins; each service owns its DB; use [[event-driven-systems|events]]/sagas.
- **Ops**: needs [[service-discovery-heartbeats|discovery]], [[api-design|gateway]], [[anomaly-detection|observability]], CI/CD, [[containers|containers]]/orchestration.

## Interview stance
"**Start monolith**, extract microservices only when scaling or team boundaries demand it. Premature microservices add distributed-systems pain for no benefit." (Monolith-first.)

## Related
[[monolith-migration]] · [[event-driven-systems]] · [[api-design]] · [[containers]] · [[service-discovery-heartbeats]]

---
Source: [takeUforward roadmap](https://youtu.be/qYhRvH9tJKw)



# How Monoliths Are Migrated

> [!abstract] TL;DR
> You don't rewrite a monolith into microservices in one "big bang." You carve pieces off **incrementally** while the system stays live — most famously with the **Strangler Fig** pattern.

## Strangler Fig pattern
Put a **proxy/[[api-design|gateway]]** in front of the monolith. Route one capability at a time to a new service; the monolith shrinks as new services grow around it, until it's "strangled" away.
1. Identify a bounded capability (e.g. "payments").
2. Build it as a new service.
3. Route that traffic to the new service via the proxy.
4. Repeat; retire monolith code as it's replaced.

## Splitting the data (the hard part)
- Each service should **own its data** — but the monolith has one shared DB.
- Techniques: **[[database-migrations|database splitting]]**, dual-write + backfill, **[[event-driven-systems|event-driven]]** sync, the **outbox** pattern.
- Expect **[[data-consistency|eventual consistency]]** across services.

## How to choose boundaries
Split along **business capabilities / bounded contexts** (Domain-Driven Design), not technical layers. High-change or independently-scaling areas go first.

## Pitfalls
- Splitting too fine ("nano-services") → chatty network calls.
- A **distributed monolith** — services so coupled they must deploy together (worst of both).

## Interview note
"Strangler Fig behind a gateway, split by bounded context, hardest part is decomposing the shared database."

## Related
[[microservices-vs-monoliths]] · [[database-migrations]] · [[api-design]] · [[event-driven-systems]]

---
Source: [takeUforward roadmap](https://youtu.be/rckfN7xFig0)



---

# API Gateways


# How Are APIs Designed?

> [!abstract] TL;DR
> Good API design = a clear, consistent, versioned contract between client and server. Plus an **API gateway** as the single front door handling cross-cutting concerns.

## API styles
| Style | Best for |
|---|---|
| **REST** | Resource CRUD over HTTP; simple, cacheable |
| **GraphQL** | Client picks exact fields; avoids over/under-fetching |
| **gRPC** | Service-to-service; binary/HTTP2, fast, streaming |

## REST design principles
- **Resource-oriented** URLs (`/users/123/orders`), nouns not verbs.
- Correct **[[http|HTTP methods]]** & **status codes**.
- **Versioning** (`/v1/…`) so you don't break clients.
- **Pagination** (cursor > offset for large sets), filtering, sorting.
- **Idempotency** (esp. for retries — idempotency keys on POST).
- Consistent errors, clear auth ([[oauth]]/[[token-based-auth]]).

## API Gateway (the front door)
Single entry point in front of many services. Handles: routing, **[[distributed-rate-limiting|rate limiting]]**, [[token-based-auth|auth]], TLS termination, request aggregation, caching, logging. Keeps cross-cutting concerns out of each service.

## Interview note
"Expose a versioned REST/gRPC contract, put an API gateway in front for auth + rate limiting + routing, and make write endpoints idempotent for safe retries."

## Related
[[asynchronous-apis]] · [[http]] · [[distributed-rate-limiting]] · [[oauth]] · [[microservices-vs-monoliths]]

---
Source: [takeUforward roadmap](https://youtu.be/_YlYuNMTCc8)



# What Are Asynchronous APIs?

> [!abstract] TL;DR
> APIs where the client doesn't block waiting for a slow result. The server accepts the request, returns immediately, and the client gets the result later (polling, webhook, or push).

## Why async
Some work is slow (video encode, report generation, ML inference). Blocking the client wastes connections and risks timeouts/[[cascading-failures]]. Async returns fast and does the work via a [[message-queues|queue]].

## Patterns for returning the result
| Pattern | How | Trade-off |
|---|---|---|
| **Polling** | Return `202 Accepted` + a status URL; client polls | Simple; wasteful, laggy |
| **Long polling** | Server holds the request until data is ready | Fewer requests; ties up connections |
| **Webhooks (callback)** | Server calls the client's URL when done | Efficient; client must expose an endpoint |
| **WebSockets / SSE** | Persistent connection, server pushes | Real-time; stateful connections to manage |

## Typical async flow
`POST /jobs → 202 + jobId` → work goes on a [[message-queues|queue]] → worker processes → result stored → client notified (webhook) or polls `GET /jobs/{id}`.

## Interview note
"For long-running work, accept with `202` and a job id, process off a queue, and return the result via webhook (or WebSocket for real-time). Keep the request path fast."

## Related
[[api-design]] · [[message-queues]] · [[event-driven-systems]] · [[http]]

---
Source: [takeUforward roadmap](https://www.youtube.com/watch?v=I8FeITQvLAk)



---

# Authentication


# OAuth

> [!abstract] TL;DR
> OAuth 2.0 is a **delegated authorization** protocol: it lets an app access a user's resources on another service **without the user sharing their password** ("Log in with Google"). It's about *access*, not identity.

## The problem it solves
"Let App X read my Google contacts" — without giving App X your Google password. OAuth issues a **scoped, revocable access token** instead.

## The 4 roles
- **Resource Owner** — the user.
- **Client** — the app wanting access.
- **Authorization Server** — issues tokens (e.g. Google).
- **Resource Server** — holds the data (e.g. Contacts API).

## Authorization Code flow (most common)
1. App redirects user to the auth server.
2. User logs in + consents to **scopes**.
3. Auth server returns a short-lived **authorization code**.
4. App exchanges code (+ client secret) for an **access token** (and **refresh token**).
5. App calls the API with the access token.
(**PKCE** adds security for mobile/SPA clients.)

## Tokens
- **Access token** — short-lived, sent on each request (often a [[token-based-auth|JWT]]).
- **Refresh token** — long-lived, used to get new access tokens without re-login.

## OAuth vs OpenID Connect
- **OAuth 2.0** = authorization (what you can access).
- **OIDC** = an identity layer on top (who you are) → adds an **ID token**. "Log in with…" uses OIDC.

## Related
[[token-based-auth]] · [[access-control-lists]] · [[api-design]] · [[http]]

---
Source: [takeUforward roadmap](https://www.youtube.com/watch?v=65-6asTjuB8)



# Token Based Auth

> [!abstract] TL;DR
> Instead of the server storing a session per user, the client holds a **signed token** (often a JWT) and sends it on every request. The server verifies the signature — **stateless**, which scales horizontally.

## Session vs token
| | Session-based | Token-based (JWT) |
|---|---|---|
| Server state | Stores session in DB/cache | **Stateless** — nothing stored |
| Scaling | Sticky sessions / shared store | Any server can verify |
| Revocation | Easy (delete session) | Hard (token valid until expiry) |
| Payload | Session id only | Claims embedded in token |

Stateless tokens are why they suit [[microservices-vs-monoliths|microservices]] and horizontally scaled, [[threads|stateless]] services.

## JWT structure
`header.payload.signature` (base64url).
- **Header** — algorithm/type.
- **Payload** — claims (user id, roles, `exp` expiry). *Readable, not encrypted — never put secrets in it.*
- **Signature** — HMAC or RSA over header+payload; proves it wasn't tampered with.

## The revocation problem
Because the server keeps no state, you can't easily "log out" a JWT before it expires. Mitigations:
- **Short-lived access tokens** + long-lived **refresh tokens**.
- A **denylist** of revoked token ids (reintroduces some state).
- Rotate signing keys.

## Security must-dos
Always HTTPS; short expiry; validate signature + `exp` + issuer/audience; store safely (httpOnly cookie vs localStorage trade-offs).

## Related
[[oauth]] · [[access-control-lists]] · [[api-design]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/security-in-distributed-systems/token-based-auth)



# Access Control Lists and Rule Engines

> [!abstract] TL;DR
> Once auth**entication** proves *who* you are ([[oauth]]/[[token-based-auth]]), authoriz**ation** decides *what you can do*. ACLs and rule engines are two ways to model those permissions.

## AuthN vs AuthZ
- **Authentication** — who are you? (login, token)
- **Authorization** — are you allowed to do this? (permissions)

## Access Control List (ACL)
A list attached to each **resource** naming who can do what: `file.txt → {alice: read/write, bob: read}`. Fine-grained and per-object, but hard to manage at scale (permissions scattered everywhere).

## Models compared
| Model | Idea | Best for |
|---|---|---|
| **ACL** | Per-resource allow list | Fine-grained, few resources |
| **RBAC** | Permissions grouped into **roles**; users get roles | Most apps (admin/editor/viewer) |
| **ABAC** | Rules over **attributes** (user, resource, context/time) | Dynamic, context-aware policy |
| **ReBAC** | Permission via **relationships** (Google Zanzibar) | Social/sharing graphs |

## Rule engines
Externalize authorization into a **policy engine** (e.g. Open Policy Agent) that evaluates rules like `allow if user.role == 'admin' AND resource.owner == user.id`. Keeps policy out of app code, centrally auditable and changeable.

## Interview note
"Default to **RBAC** for simplicity; add **ABAC**/rule-engine when decisions depend on attributes/context. ACLs for truly per-object sharing."

## Related
[[oauth]] · [[token-based-auth]] · [[api-design]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/security-in-distributed-systems/access-control-lists-and-rule-engines)



---

# System Design Tradeoffs


# Trade-off: Pull vs. Push

> [!abstract] TL;DR
> **Pull** — the client asks for data when it wants it. **Push** — the server sends data as it happens. Pull is simple and scalable; push is real-time but stateful.

## Comparison
| | Pull (client polls) | Push (server sends) |
|---|---|---|
| Freshness | Lag (poll interval) | Real-time |
| Server load | Wasted empty polls | Only on real events |
| Connections | Stateless | Persistent (WebSocket/SSE) |
| Complexity | Simple | Must track connections, handle offline |

## Classic example: news feed
- **Fan-out on write (push)** — when you post, write into every follower's feed. Fast reads, but a celebrity with 100M followers = write storm.
- **Fan-out on read (pull)** — build the feed when a user opens the app. Cheap writes, heavier reads.
- **Hybrid** — push for normal users, pull for celebrities. (This is what real systems do.)

## When to choose
- **Pull** — data changes slowly, many clients, simplicity matters.
- **Push** — chat, live scores, notifications, collaborative editing.

## Related
[[publisher-subscriber-model]] · [[asynchronous-apis]] · [[caching]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/system-design-tradeoffs/pull-vs-push-architectures)



# Trade-off: Memory vs. Latency

> [!abstract] TL;DR
> You can usually make things faster by **using more memory/storage** (precompute, cache, index, denormalize) — or save space at the cost of doing more work per request. Space ⇄ time.

## The core idea
Latency drops when the answer is already sitting in fast storage; that costs memory. Save memory and you recompute/refetch → higher latency.

## Examples of spending memory to cut latency
| Technique | Memory cost | Latency win |
|---|---|---|
| **[[caching]]** | Store hot data in RAM | Skip the DB |
| **[[database-indexes]]** | Extra index structures | O(log n) not O(n) |
| **Denormalization** | Duplicate data | No joins at read time |
| **Precomputation / materialized views** | Store results | No compute on read |
| **[[tradeoff-pull-vs-push|Fan-out on write]]** | Store per-user feeds | Instant feed reads |

## The other direction (save memory)
Compression, [[bloom-filters|probabilistic structures]], computing on demand, sampling — all trade CPU/latency to shrink footprint.

## Interview note
"Given a read-heavy, latency-sensitive path, I'd trade memory for speed — cache + precompute. If storage/cost is the constraint, I'd compute on demand or compress and accept higher latency."

## Related
[[caching]] · [[database-indexes]] · [[tradeoff-throughput-vs-latency]] · [[capacity-estimation]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/system-design-tradeoffs/memory-vs-latency)



# Trade-off: Throughput vs. Latency

> [!abstract] TL;DR
> **Latency** = time for one request. **Throughput** = requests handled per second. Optimizing one can hurt the other — batching raises throughput but adds latency; per-request handling lowers latency but caps throughput.

## Definitions
- **Latency** — how long a single operation takes (measure **p50/p95/p99**, not the average).
- **Throughput** — total work per unit time (QPS, records/sec).

## Why they conflict
| Technique | Throughput | Latency |
|---|---|---|
| **Batching** | ↑ (amortize overhead) | ↑ (wait to fill a batch) |
| **Buffering / queuing** | ↑ (smooth spikes) | ↑ (time in queue) |
| **Parallelism** | ↑ | ↓ or neutral |
| **Per-request, no batching** | ↓ | ↓ |

Under heavy load, queues fill → latency climbs even if throughput is maxed (Little's Law: `L = λ × W`).

## The restaurant analogy
Cooking 10 orders at once = more meals/hour (throughput) but each diner waits longer (latency). Cooking one at a time = fast per diner, fewer served.

## Interview note
"Latency-critical path (checkout) → minimize batching, add capacity. Bulk/analytics pipeline → batch aggressively for throughput. State the p99 target."

## Related
[[tradeoff-memory-vs-latency]] · [[message-queues]] · [[capacity-estimation]] · [[transaction-isolation-levels]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/system-design-tradeoffs/throughput-vs-latency)



# Trade-off: Consistency vs. Availability

> [!abstract] TL;DR
> The **CAP** trade-off. During a network partition you must choose: reject requests to stay **consistent** (CP), or keep serving possibly-stale data to stay **available** (AP). See [[data-consistency]] for the fuller model.

## CAP recap
When the network partitions (nodes can't talk):
- **CP** — refuse/block writes so no one reads stale data. Consistent, but some requests fail.
- **AP** — keep answering with whatever each node has. Available, but data may be stale/divergent.

(No partition → you can have both C and A.)

## Which to pick — by domain
| Choose consistency (CP) | Choose availability (AP) |
|---|---|
| Money / payments / inventory | Social feeds, likes, views |
| Booking (double-book is bad) | Product catalog, recommendations |
| Auth / permissions | Analytics, telemetry |

## Real systems are tunable
Many stores let you choose **per operation** (quorum levels): a shopping app might use **strong** consistency for checkout and **eventual** for the "people also bought" widget.

## PACELC extension
Even with no partition (**E**lse), you still trade **L**atency vs **C**onsistency — strong consistency costs coordination time.

## Interview note
"Name the CAP choice explicitly per feature. Default AP for scale/UX, CP where correctness is non-negotiable (money)."

## Related
[[data-consistency]] · [[data-consistency-levels]] · [[data-replication]] · [[tradeoff-latency-vs-accuracy]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/system-design-tradeoffs/consistency-vs-availability)



# Trade-off: Latency vs. Accuracy

> [!abstract] TL;DR
> Often you can return a **fast, approximate** answer or a **slow, exact** one. For many features, "close enough right now" beats "perfect but late."

## The idea
Exact answers may need scanning all data or strong coordination (slow). Approximations use sampling, [[bloom-filters|probabilistic structures]], or cached/precomputed values (fast).

## Approximation techniques
| Technique | Trades accuracy for speed by… |
|---|---|
| **Sampling** | Computing on a subset |
| **[[bloom-filters|Bloom filters]] / HyperLogLog** | Probabilistic membership / cardinality |
| **Approx / stale counts** | Serving cached or eventually-consistent numbers |
| **Top-K heavy hitters** | Tracking only the most frequent items |
| **Approximate nearest neighbor (ANN)** | Near-best matches, not exact |

## When approximate is fine (vs not)
- ✅ Fine: view counts, "trending," analytics dashboards, recommendations, autocomplete.
- ❌ Not fine: bank balance, inventory at checkout, billing.

## Classic example
YouTube view counts and Twitter follower counts are **approximate/eventually consistent** at scale — exact real-time counting across shards would be far too slow/expensive.

## Interview note
"For non-critical metrics I'd serve approximate/cached values for speed, and reserve exact computation for money/inventory."

## Related
[[bloom-filters]] · [[tradeoff-consistency-vs-availability]] · [[caching]] · [[capacity-estimation]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/system-design-tradeoffs/latency-vs-accuracy)



# Trade-off: SQL vs. NoSQL Databases

> [!abstract] TL;DR
> The classic data-store decision. **SQL** = structure, joins, strong [[relational-databases|ACID]]. **NoSQL** = flexible schema, horizontal scale, high write throughput. Pick by access pattern, not fashion. (Deep dives: [[relational-databases]], [[nosql-databases]].)

## Decision table
| Factor | SQL | NoSQL |
|---|---|---|
| Schema | Fixed, structured | Flexible / schemaless |
| Relationships/joins | Strong | Weak (denormalize) |
| Consistency | ACID (strong) | Often eventual (BASE) |
| Scaling | Vertical / hard sharding | Horizontal by design |
| Write throughput | Moderate | Very high ([[nosql-optimization|LSM]]) |
| Query flexibility | Rich (SQL) | Limited to access pattern |

## Choose SQL when
Structured, related data with transactional correctness: payments, orders, users, inventory, anything needing joins + [[transaction-isolation-levels|strong isolation]].

## Choose NoSQL when
- **Key-value** — sessions, [[caching|caching]] (Redis).
- **Document** — flexible/evolving schema (MongoDB).
- **Wide-column** — massive write volume, time-series (Cassandra).
- **Graph** — relationship-heavy queries (Neo4j).

## Polyglot persistence
Real systems use **both** — SQL for core transactional data, NoSQL for scale-out/flexible parts. Don't force one store to do everything.

## Interview note
"Structured + transactional → SQL. Huge scale, flexible schema, or simple key access → NoSQL. State the access pattern first, then pick."

## Related
[[relational-databases]] · [[nosql-databases]] · [[nosql-optimization]] · [[sharding]] · [[data-consistency]]

---
Source: [InterviewReady (via takeUforward roadmap)](https://interviewready.io/learn/system-design-course/system-design-tradeoffs/sql-vs-nosql-databases)



---

# Practice Problems


# System Design — Practice Problems

> [!abstract] How to use this
> These 17 are **design case studies**, not concepts to memorize. Watch each video, then **fill in the framework below in your own words** — that's where the learning happens. I've left them as a tracker on purpose: a fabricated "answer key" would teach you wrong patterns. One note per problem, created as you do them.

## The reusable framework (apply to every problem)
Copy this into a new note per case study:

```markdown
1. Requirements
   - Functional: (what it must do)
   - Non-functional: scale, latency, availability, consistency
2. Capacity estimation  → [[capacity-estimation]]
   - DAU, read/write QPS, storage, bandwidth
3. API design           → [[api-design]]
4. Data model           → [[relational-databases]] / [[nosql-databases]]
5. High-level design (draw boxes: client → LB → services → DB/cache/queue)
6. Deep dives (pick 1–2 hard parts)
7. Bottlenecks & scaling → [[caching]] · [[sharding]] · [[data-replication]] · [[load-balancing]]
8. Trade-offs made       → [[tradeoff-consistency-vs-availability]] etc.
```

## The 17 problems + what each teaches

### Video-based (takeUforward)
| # | Problem | Key concepts to nail |
|---|---|---|
| 1 | [Live-Streaming App](https://youtu.be/m8Icp_Cid5o) | [[content-delivery-networks\|CDN]], video pipeline, fan-out |
| 2 | [Instagram](https://youtu.be/QmX2NPkJTKg) | Feed, [[tradeoff-pull-vs-push\|fan-out]], media storage |
| 3 | [Tinder](https://youtu.be/tndzLznxq40) | [[location-based-databases\|geo]], matching, recommendations |
| 4 | [WhatsApp](https://youtu.be/vvhC64hQZMk) | Real-time messaging, [[tradeoff-pull-vs-push\|push]], delivery receipts |
| 5 | [TikTok](https://youtu.be/07BVxmVFDGY) | Recommendation feed, video CDN, ranking |
| 6 | [Online Coding Judge — Pt 1](https://www.youtube.com/watch?v=eg0nlYcbLpo) | Sandboxing, [[message-queues\|queues]], [[containers]] |
| 7 | [Online Coding Judge — Pt 2](https://www.youtube.com/watch?v=07jkn4jUtso) | Scaling execution, result flow |
| 8 | [UPI Payments](https://www.youtube.com/watch?v=QpLy0_c_RXk) | [[transaction-isolation-levels\|ACID]], idempotency, [[tradeoff-consistency-vs-availability\|CP]] |
| 9 | [IRCTC (train booking)](https://www.youtube.com/watch?v=j3etJx7M0Sc) | Concurrency, seat locking, no double-booking |
| 10 | [Netflix Video Onboarding Pipeline](https://youtu.be/x9Hrn0oNmJM) | Encoding pipeline, [[event-driven-systems]], storage |
| 11 | [Doordash](https://www.youtube.com/watch?v=DH2-vDPFiE4) | [[location-based-databases\|geo]] matching, 3-sided marketplace |
| 12 | [Amazon Online Shops](https://www.youtube.com/watch?v=2BWr0fsDSs0) | Catalog, cart, inventory, checkout consistency |

### Text-based (InterviewReady)
| # | Problem | Key concepts to nail |
|---|---|---|
| 13 | [Google Maps](https://interviewready.io/learn/system-design-course/design-a-location-based-service-like-google-maps/requirements-of-a-map-application?_aff=TAKEUFORWARD) | [[location-based-databases\|geo indexing]], routing, tiles |
| 14 | [Gmail](https://interviewready.io/learn/system-design-course/design-an-emailing-service-like-gmail/scope_and_requirement_setting?_aff=TAKEUFORWARD) | Storage, search, [[sharding]] |
| 15 | [Chess Website](https://interviewready.io/learn/system-design-course/chess-design-building-a-highly-scalable-turn-based-gaming-website/requirements_of_a_chess_website?_aff=TAKEUFORWARD) | Turn-based state, real-time, matchmaking |
| 16 | [Uber](https://interviewready.io/learn/system-design-course/design-a-cab-aggregator-app-like-uber/requirements-of-a-cab-aggregator?_aff=TAKEUFORWARD) | [[location-based-databases\|geo]], dispatch, surge |
| 17 | [Google Docs](https://interviewready.io/learn/system-design-course/google-docs-collaborative-editor-design/Google-Docs-Requirements?_aff=TAKEUFORWARD) | Collaborative editing, CRDT/OT, [[tradeoff-consistency-vs-availability\|consistency]] |

## Additional resources (from the roadmap)
- [InterviewReady course](https://interviewready.io/?_aff=TAKEUFORWARD&source_id=striver_blog)
- [System Design Resources (GitHub)](https://github.com/InterviewReady/system-design-resources)
- *Designing Data-Intensive Applications* — the canonical book

## Related
[[system-design-eli10]] · [[what-is-system-design]] · [[capacity-estimation]] · [[api-design]]



---

# Quick Revision (Explained Like You're 10)


# System Design, Explained Like You're 10 🍕

> [!abstract] The one big idea
> Every topic below is just a piece of running a **super-popular pizza shop**. Start with one kid making pizza in a kitchen. As more and more people want pizza, you have to get clever. *That cleverness is system design.*

This note covers all 12 topics in kid-language **plus the grown-up words** you need to remember. Full detail lives in each linked note.

---

## 1. What is System Design? 🏗️
[[what-is-system-design]]

**Kid version:** You're opening a pizza shop. Before cooking, you plan: Where's the kitchen? How many ovens? Who takes orders? What if 1,000 people show up at once? Planning all of that *before* problems happen = system design.

**Grown-up words:**
- **Functional** = *what* it does ("make pizza, take orders").
- **Non-functional** = *how well* ("fast, never closed, never loses an order"). ← this is where interviews are won.
- There's never a perfect plan, only **trade-offs**: fast *or* cheap *or* simple — pick.

**Remember:** Design = plan for scale, speed, and staying open, and always name the trade-off.

---

## 2. Vertical vs Horizontal Scaling 💪
[[horizontal-vs-vertical-scaling]]

**Kid version:** Too many pizza orders! Two ways to cook faster:
- **Vertical (scale up):** buy ONE giant super-oven. Fast, but there's a biggest-oven-in-the-world limit, and if it breaks, no pizza at all. 😱
- **Horizontal (scale out):** buy LOTS of normal ovens. Add as many as you want, and if one breaks the others keep going. 👍

**Grown-up words:** Scale up = bigger machine. Scale out = more machines. Real systems scale **out**, put a **load balancer** (a host who sends each customer to a free oven), and keep workers **stateless** (any oven can handle any order).

**Remember:** More small ovens beats one giant oven.

---

## 3. Capacity Estimation 🔢
[[capacity-estimation]]

**Kid version:** Before opening, you guess: "About how many pizzas per hour? How much cheese do I need? How big a fridge?" Guessing with rough math so you buy the right amount.

**Grown-up words:** Estimate **QPS** (orders per second), **storage** (how much data you keep), **bandwidth** (how much you send). Round hard, split **reads vs writes**. Handy fact: a day ≈ 100,000 seconds, so *per-day ÷ 100,000 = per-second*.

**Remember:** Do rough math first so you scale the *right* thing.

---

## 4. What is HTTP? 🗣️
[[http]]

**Kid version:** HTTP is the **waiter**. You (browser) say "One pizza please" (**request**). The waiter brings pizza or says "sorry, sold out" (**response**). The waiter forgets you the moment they walk away — every order starts fresh.

**Grown-up words:** HTTP = **stateless request/response**.
- Methods: **GET** (read), **POST** (create), **PUT/PATCH** (change), **DELETE** (remove).
- Status codes: **2xx** yay, **3xx** go-look-elsewhere, **4xx** *your* mistake (404 not found), **5xx** *shop's* mistake.
- **HTTPS** = HTTP whispering in secret code (TLS) so no one spies.

**Remember:** HTTP = polite waiter who forgets you after every order.

---

## 5. The TCP/IP Stack 📮
[[tcp-ip-stack]]

**Kid version:** How does your order actually reach the shop across town? Like mailing a letter, it passes through layers: you write it → put it in an envelope → the post office routes it → the mail truck drives it. Each layer has ONE job.

**Grown-up words:** Layers = **Application (HTTP)** → **Transport (TCP/UDP)** → **Internet (IP)** → **Link (wire/wifi)**.
- **TCP** = careful mail: confirms delivery, resends lost letters, keeps order. (web, APIs)
- **UDP** = fast mail: fire and forget, some may get lost. (video calls, games)
- TCP starts with a **3-way handshake**: "Hi? / Hi back? / Great!" before talking.

**Remember:** Layers = envelopes inside envelopes. TCP = careful, UDP = fast.

---

## 6. What Happens When You Enter Google.com? 🌍
[[what-happens-when-you-visit-google]]

**Kid version:** This is the WHOLE journey of ordering one pizza, start to finish:
1. **DNS** — you know the shop's *name* but not its address; you ask a phone book for the address. 📖
2. **TCP handshake** — you call and say hi, they say hi back.
3. **TLS** — you switch to secret code so nobody hears your order.
4. **HTTP** — you finally say "one pizza!"
5. **Kitchen** — the host (load balancer) picks a free cook, who maybe grabs a ready pizza from the warmer (**cache**) or checks the recipe book (**database**).
6. **Delivery + render** — pizza arrives; you unbox and eat (browser draws the page).

**Grown-up words:** DNS → TCP → TLS → HTTP → server (LB → app → cache/DB) → response → render. This one question secretly tests the *entire* stack.

**Remember:** Name → address → hello → secret code → order → kitchen → eat.

---

## 7. Relational Databases (SQL) 🗄️
[[relational-databases]]

**Kid version:** A super-strict filing cabinet. Every customer form must be filled in *exactly* right — no missing boxes. Everything is neat, and forms connect to each other ("this order belongs to that customer").

**Grown-up words:** Data in **tables** with a fixed **schema**, linked by **keys**, queried with **SQL**. Gives **ACID** = money-safe promises (all-or-nothing, always valid, no mix-ups, never lost). Great for correctness (payments, orders). Downside: hard to spread writes across many machines.

**Remember:** SQL = strict, tidy, safe filing cabinet. Use it when mistakes must never happen.

---

## 8. Database Indexes 🔎
[[database-indexes]]

**Kid version:** Your recipe book has 500 pages. To find "pepperoni," do you read every page? No — you flip to the **index** at the back and jump straight there.

**Grown-up words:** An index (usually a **B-tree**) lets the database jump to rows instead of scanning everything — turns slow O(n) into fast O(log n). **Trade-off:** faster reads, but **slower writes** and more storage (every new page means updating the index). Don't index everything.

**Remember:** Index = shortcut to find stuff fast; costs a little extra work when adding stuff.

---

## 9. NoSQL Databases 🧸
[[nosql-databases]]

**Kid version:** Instead of the strict filing cabinet, a giant **toy box**. Throw anything in, any shape, no strict form. Super easy to add a *hundred* more toy boxes when you have tons of stuff.

**Grown-up words:** Non-relational stores; flexible schema; scale **out** easily. Types: **key-value** (Redis), **document** (MongoDB), **wide-column** (Cassandra), **graph** (Neo4j). Often **eventually consistent** (copies catch up in a moment). 

**SQL vs NoSQL:** strict + safe + connected → **SQL**. Huge + flexible + simple lookups → **NoSQL**. (Real apps use both!)

**Remember:** SQL = tidy cabinet. NoSQL = giant flexible toy box that's easy to copy.

---

## 10. What is a Cache? 🍪
[[caching]]

**Kid version:** Instead of walking to the far kitchen every time you're hungry, keep some cookies **in your pocket**. Grab-and-go for the snacks you eat most. Way faster.

**Grown-up words:** A cache stores hot data in a **faster/closer** layer (like **Redis**, or a **CDN** at the "edge" near users) so most requests skip the slow database. Works because of **locality** (a few things get used a lot). Strategy: **cache-aside** (check pocket first). Hard parts: **invalidation** (what if a cookie goes stale?) and **stampede** (everyone raids the kitchen at once). Measure with **hit ratio**.

**Remember:** Cache = snacks in your pocket. Fast, but you must keep them fresh. (This is the same idea as the CPU **Cache Memory** note — just a different layer.)

---

## 11. What is Thrashing? 🌀
[[thrashing]]

**Kid version:** One tiny table, but 20 kids doing homework. Only 2 can sit at a time, so everyone keeps swapping seats — stand up, sit down, stand up — and **nobody actually finishes homework**. Busy, but useless.

**Grown-up words:** When the **working set** (stuff you're using now) doesn't fit in **RAM**, the computer spends all its time swapping pages to slow disk instead of working. Throughput collapses. Fix: fewer things at once, or more RAM. Same idea as a cache with a hit ratio too low to help.

**Remember:** Thrashing = so much swapping that no real work gets done.

---

## 12. What are Threads? 🧑‍🍳🧑‍🍳
[[threads]]

**Kid version:** One cook is slow. Hire **many cooks in the same kitchen** — one chops, one bakes, one boxes — all at once. But if two grab the same knife at the same time... uh oh. 🔪

**Grown-up words:** A **thread** = one worker inside a **process**. Many threads share memory and run at once = **concurrency** (juggling many things) / **parallelism** (truly at the same time on many cores). Danger: **race conditions** (two threads clash) and **deadlock** (both wait forever). Fix with **locks**.

**Remember:** Threads = many cooks in one kitchen. Powerful, but they must not grab the same knife.

---

## 🎯 Whole thing in 6 sentences
1. **System design** = planning your pizza shop for huge crowds.
2. Serve more people with **more ovens** (horizontal scaling) behind a **host** (load balancer), and **guess demand first** (capacity estimation).
3. Orders travel by polite **waiter** (HTTP) through layers of **mail** (TCP/IP), and one order's full journey is the **"what happens when you visit Google"** story (DNS→TCP→TLS→HTTP→render).
4. Store facts in a **strict cabinet** (SQL) or a **flexible toy box** (NoSQL), and find them fast with an **index**.
5. Keep hot stuff in your **pocket** (cache) so you skip the slow kitchen.
6. Watch out for **too-much-swapping** (thrashing) and use **many cooks carefully** (threads).

> [!tip] Best revision trick
> Cover the grown-up words and try to teach each 🍕 story out loud. Anything you *can't* explain simply → that's your weak spot for **2026-07-27**.

