001 Notes
System Design Interview Notes
SD.1 — All types of API
REST
GET /users/123 → 200 + user JSON
POST /users → 201 + new user
PUT /users/123 → 200 (full replace)
PATCH /users/123 → 200 (partial)
DELETE /users/123 → 204
GraphQL
query {
user(id: 123) {
name
posts(last: 5) { title comments(last: 2) { author { name } } }
}
}
gRPC
service UserService {
rpc GetUser(GetUserRequest) returns (User);
rpc StreamUsers(stream UserFilter) returns (stream User);
}
WebSocket
client → server: HTTP Upgrade: websocket
server → client: 101 Switching Protocols
[binary or text frames in either direction]
Server-Sent Events (SSE)
HTTP/1.1 200 OK
Content-Type: text/event-stream
data: hello
event: tick
data: {"time": 123}
Polling / long polling
Webhooks
SOAP
<soap:Envelope>
<soap:Body><GetUser><Id>123</Id></GetUser></soap:Body>
</soap:Envelope>
JSON-RPC / XML-RPC
{"jsonrpc":"2.0","method":"add","params":[1,2],"id":1}
MQTT
Comparison table
| API style | Transport | Direction | Shape | Use case |
|---|---|---|---|---|
| REST | HTTP/1.1 or 2 | request/response | client-defined URL, server-defined body | public API, CRUD |
| GraphQL | HTTP | request/response (+ WS subscriptions) | client-defined query | client-driven aggregation |
| gRPC | HTTP/2 | uni or bi-streaming | proto-defined | internal microservices |
| WebSocket | TCP after HTTP upgrade | full duplex | freeform | chat, games, trading |
| SSE | HTTP/1.1 or 2 | server → client | freeform text events | dashboards, notifications |
| Webhook | HTTP | server → server | provider-defined | event integration |
| SOAP | HTTP/other | request/response | strict XML | enterprise legacy |
| MQTT | TCP | pub/sub | tiny binary | IoT |
SD.2 — API versioning
Why version
Strategies
GET /v1/users/123
GET /v2/users/123
GET /users/123
Accept: application/vnd.acme.v2+json
GET /users/123?api_version=2
GET https://v2.api.acme.com/users/123
Semantic versioning
Compatibility patterns
gRPC specifics
Deprecation policy
Real-world example: Stripe
SD.3 — MongoDB vs others — read/write performance
What MongoDB is
Write performance
| DB | Typical writes/sec (single shard, durable) | Why |
|---|---|---|
| Postgres | 5K–30K | row-level locks, WAL, MVCC |
| MySQL (InnoDB) | 5K–30K | similar to PG |
| MongoDB | 5K–20K | document-level locking |
| Cassandra | 50K–200K | log-structured, no read-before-write on insert |
| DynamoDB | 10K–40K per partition | provisioned, request-routed |
| ScyllaDB | 100K–500K | C++ rewrite of Cassandra, shard-per-core |
Read performance
| DB | Read characteristics |
|---|---|
| Postgres | full SQL, complex joins fast with planner, MVCC reads |
| Mongo | denormalized docs avoid joins, $lookup is slow |
| Cassandra | single-partition reads fast, cross-partition is fan-out |
| Redis | in-memory, sub-ms |
| DynamoDB | partition+sort key reads fast; scan is slow |
| Elasticsearch | full-text search, aggregations on terms |
Why Mongo wins / loses
Sharding
Replica sets
Disk layout
SD.4 — Caches
What caching is for
Cache tiers in a typical web stack
| Tier | Latency | Capacity | What |
|---|---|---|---|
| CPU L1 | 1 ns | 32 KB | per-core, code+data |
| CPU L2 | 4 ns | 256 KB–1 MB | per-core |
| CPU L3 | 12 ns | 30 MB | shared per socket |
| OS page cache | 50 ns | RAM | file contents |
| App in-process | 100 ns | RAM | object cache |
| Local Redis/memcached | 100 μs | per-node RAM | cluster cache |
| Distributed cache (cluster) | 500 μs | aggregate RAM | hot data |
| Database | 1–10 ms | TB | source of truth |
| CDN | 10–50 ms (first hop) | global | static assets, API responses |
| Browser | 0 (local disk) | per-user | per-user assets |
Local vs global cache
Write strategies
| Strategy | Behavior | Trade |
|---|---|---|
| Write-through | write goes to cache AND DB synchronously | safe; slow writes; cache always coherent |
| Write-back | write to cache, flush later | fast writes; data loss on cache failure |
| Write-around | write goes to DB only; cache populated on read | safe for write-heavy data; first read slow |
| Read-through | cache miss fetches from DB and populates | cleanest separation |
| Cache-aside | app manages cache miss + repopulate | most flexible; most bug-prone |
Eviction policies
Indexing inside the cache
Hot data
Cache stampede / dogpile
Negative caching
SET user:9999 "MISSING" EX 60
Cache invalidation patterns
Distributed cache consistency
T1 reads X (miss), reads DB → 5
T2 writes X = 6 to DB, invalidates cache (no-op since not in cache yet)
T1 inserts 5 into cache ← stale
CDN
SD.5 — Kafka deep dive
What Kafka is
Topology
Producer ──┐ ┌── Consumer (group A, instance 1)
Producer ──┤ ├── Consumer (group A, instance 2)
│ │
▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Broker1 │ │ Broker2 │ │ Broker3 │
└─────────┘ └─────────┘ └─────────┘
▲ ▲ ▲
└─── controller (KRaft or ZK)
Topics and partitions
topic "orders":
partition 0: [r0, r1, r2, r3, ...]
partition 1: [s0, s1, s2, ...]
partition 2: [t0, t1, t2, ...]
Partition assignment by key
producer.send("orders", key="user_123", value=order_json)
Brokers
Replication
acks=0 → fire-and-forget; producer doesn't wait. Data loss on failure.
acks=1 → leader writes locally and ACKs. Leader crash before replication = data loss.
acks=all → leader waits for all ISR to ACK. Safest. min.insync.replicas=2 means at least 2 ISR must exist for write to succeed.
Log layout
/var/kafka/orders-0/
00000000000000000000.log # records 0..N
00000000000000000000.index # offset → byte
00000000000000000000.timeindex # time → offset
00000000000123456789.log # records N..M
...
Producer guarantees
Consumer groups
group "billing":
instance A → partitions 0, 1
instance B → partitions 2, 3
Offsets
Why Kafka is fast
Log compaction
key=user:1, value={name: "Alice", balance: 100} ← discarded after newer one
key=user:1, value={name: "Alice", balance: 150} ← kept (latest for key)
key=user:2, value=...
Coordinator (KRaft / ZooKeeper)
Common configuration pitfalls
Mirror Maker / replication across clusters
SD.6 — Redis vs Memcached vs others
Redis
SET k v EX 60
LPUSH q x; RPOP q
ZADD scores 100 alice; ZRANGE scores 0 -1 WITHSCORES
HSET user:1 name alice age 30
XADD events * type click user 123
Memcached
Decision
| Want | Use |
|---|---|
| Just a cache, raw KV, multi-core | Memcached |
| Data structures (queues, sets, sorted sets, streams) | Redis |
| Persistence | Redis |
| Pub/sub or streams | Redis |
| Rate limiting, locks, atomic ops | Redis (Lua, INCR, SETNX, Redlock) |
| Geographic / vector / search | Redis with modules |
Other in-memory systems
Use case examples
SD.7 — Zookeeper
What it is
ZAB protocol
Guarantees
Znodes
/services/db/leader-0000000042 (ephemeral sequential)
/services/db/leader-0000000043
Watches
Use cases
Limits
Alternatives
When NOT to use
SD.8 — SQS vs SNS vs RabbitMQ vs Kafka
SQS (Amazon Simple Queue Service)
SNS (Amazon Simple Notification Service)
RabbitMQ
Kafka
Comparison
| Aspect | SQS | SNS | RabbitMQ | Kafka |
|---|---|---|---|---|
| Model | queue | pub/sub | broker (exchange→queue) | log |
| Pull/push | pull | push | both | pull |
| Ordering | FIFO queue only | FIFO topic only | per queue | per partition |
| Throughput | unlimited (std) | unlimited | 10K–100K msg/s | millions msg/s |
| Latency | ~10ms | ~10ms | ~1ms | ~5ms |
| Replay | no | no | no (msg gone after ack) | yes (retention) |
| Persistent log | no | no | optional | yes |
| Routing logic | basic | topic filters | rich exchanges | partition by key |
| Ops burden | zero (managed) | zero | medium | high |
| Per-message ack | yes | n/a | yes | offset-based |
| Priorities | no | no | yes | no |
Decision tree
SD.9 — AWS-based Semantic DB (vector search)
What semantic search is
AWS options
SELECT id, content FROM docs
WHERE tenant_id = 42
ORDER BY embedding <=> '[0.1, 0.2, ...]'::vector
LIMIT 10;
Embedding pipeline
Document → Chunker → Embedding model → Vector + metadata → Vector DB
Query → Embedding model → ANN query → Top K → (rerank) → LLM context
Tuning
Hybrid retrieval
score(doc) = 1/(k + rank_bm25) + 1/(k + rank_vector)
Reranking
SD.10 — Collaborative service scaling (Sheets, Zoom)
Collaborative document (Google Sheets, Figma)
Operational Transformation (OT)
Server state: "abc"
User A inserts 'X' at position 1: "aXbc"
User B inserts 'Y' at position 2 (in original): "abYc"
Server transforms B against A: position 2 → 3 (shifted by A's insert): "aXbYc"
CRDT (Conflict-free Replicated Data Types)
Architecture pattern (OT/CRDT-based)
Client ─WS─► Edge ─► Doc Service (shard by doc_id)
│
├── In-memory document state
├── Op log (Kafka or DB append-only)
└── Snapshots (S3 every N ops)
Real-time media (Zoom, Google Meet)
Topologies
Simulcast / SVC
Scaling SFUs
Transport
Latency
Recording / VOD
Live streaming layer
SD.11 — WebRTC, RTSP, RTP, WebSocket, SSE, polling, QUIC, UDP
RTP (Real-time Transport Protocol)
RTSP (Real Time Streaming Protocol)
WebRTC
WebSocket
GET /chat HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: ...
SSE (Server-Sent Events)
const es = new EventSource('/events');
es.onmessage = (e) => console.log(e.data);
Polling
Client: GET /messages?since=1234
Server: 200 OK [messages]
sleep 5s
repeat
Long polling
QUIC
UDP congestion control
SD.12 — Inter-region consistency
The fundamental problem
Replication patterns
Single-region with async cross-region replicas
Multi-master (active-active) with last-writer-wins
Multi-master with CRDT merge
Multi-region with strong consistency
Reading
Cross-region conflict handling
Read-your-writes guarantees
Region failure / failover
SD.13 — Disaster recovery per system
RTO and RPO
Tiers
| Tier | RTO | RPO | Approach |
|---|---|---|---|
| Backup/restore | hours-days | hours | nightly snapshots; restore on DR site |
| Pilot light | hours | minutes | minimal infra always running; scale up on failover |
| Warm standby | minutes | seconds | scaled-down full stack always running |
| Multi-site active-active | seconds | zero (or near) | live traffic across regions |
Comments