~learn.
?

Foundations, on one page.

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

System Design Mastery · World 00 cheat sheet

Foundations

~/himanshufree course · systemdesignmastery.dev/

Part 1System Design Fundamentals

HLD vs LLD. High-level design is the what: components, how they interact and why. Low-level design is the how: schemas, API contracts, algorithms, error handling. Interviews start high-level, then deep-dive one or two areas.

The four-step framework. Clarify requirements (3–5 min), estimate scale (5–7), draw the high-level design (15–20), then deep dive (10–15): schema, API, critical algorithms, edge cases and failures.

Functional vs non-functional. Functional requirements say what the system does; non-functional ones say how well: uptime, latency, throughput, consistency. The non-functional ones drive architecture, technology and cost.

Sync vs async. Sync is simple with immediate feedback, but the client blocks and services couple. Async through a queue decouples, absorbs spikes and allows retries, at the cost of eventual consistency and harder debugging.

API styles. REST for CRUD and public APIs, GraphQL when clients ask for exactly the data they need, gRPC (binary Protocol Buffers) for fast internal calls, WebSocket for server push.

99.9%8.76 hours of downtime a year
99.99%52.6 minutes a year
99.999%5.26 minutes a year
<100 · <10 · <1 mstypical P99: API response, database query, cache hit
Trade-off · Synchronous vs asynchronous
SynchronousAsynchronous
FeedbackImmediateLater (ACK on receipt)
CouplingTightLoose
Traffic spikeClient waitsQueue buffers it
Use forLogin, checkout, balance checkVideo processing, emails, order fan-out
  • Designing before clarifying scope, scale and the read/write ratio.
  • Skipping non-functional requirements: they decide the architecture.
  • Diving into low-level detail before the high-level picture is agreed.

Part 2Infrastructure Building Blocks

CDN. Edge servers (PoPs) serve content near users: ~5–10 ms from a Mumbai PoP versus ~150–200 ms to a US origin. Cache static assets and identical-for-everyone responses; never user-specific data.

Versioned URLs. Put a content hash in the filename (app.a1b2c3d4.js) and cache it for a year as immutable. A deploy changes the URL, so users get fresh files with zero purge delay.

no-cache doesn't mean "don't cache". no-cache caches but revalidates (ETag, 304 Not Modified); no-store never caches; private keeps it out of the CDN; s-maxage gives the CDN its own TTL.

L4 vs L7 load balancing. L4 sees IP and port: very fast (<100 μs added), any protocol. L7 sees the whole HTTP request: routes by path, host, header or cookie and terminates TLS, adding 1–5 ms.

Shallow vs deep health checks. Point the load balancer at a shallow liveness check. A deep check that queries the database marks every server unhealthy when the DB is down; use deep checks for monitoring.

Stateless servers scale. Keep no session in server memory: sessions in Redis, data in PostgreSQL, files in S3. Then any server takes any request and a crash loses nothing.

31536000 sone year: max-age for content-hashed assets
90% hitsat 1 ms vs 50 ms DB: 5.9 ms average, 8.5x faster
11 ninesS3 durability: 99.999999999%
50–200 msfull DNS resolution with nothing cached
Trade-off · Monolith vs microservices
MonolithMicroservices
ScalingEverything togetherPer service
FailuresOne affects allIsolated
TransactionsACID is easyDistributed, hard
Start here whenSmall team, new productClear boundaries, strong DevOps
  • Caching user-specific or authenticated responses at the CDN.
  • A deep health check behind the load balancer: one database outage removes every server.
  • Microservices for a small team with unclear requirements; start with a monolith.

Part 3Back-of-the-Envelope Estimation

Per day to per second. A day is 86,400 seconds; round to 100,000. So X per day ÷ 100,000 ≈ X per second: 1 billion a day is about 10,000 a second.

The four estimates. Traffic (RPS, read/write split, peak), storage (objects × size × retention × replication), bandwidth (RPS × payload, ingress and egress) and infrastructure (servers, replicas, cache).

Latency ratios matter. L1 cache 0.5 ns, memory 100 ns, SSD random read 150 μs, HDD seek 10 ms; datacenter round trip 0.5 ms, cross-continent 150 ms. Cache aggressively, batch, and minimize round trips.

Media dominates storage. For a Twitter-like service, text is 30 GB a day but images and videos add ~7 TB a day: media is 99%+ of storage. Egress for images is why the CDN is essential.

Formulas to say out loud. RPS = daily actions ÷ 100,000. API servers = peak RPS ÷ 5,000 ÷ 0.7. Read replicas = read RPS ÷ 30,000. Cache = hot data: 20% of the total, or the last N days.

Peak = 2xaverage for normal apps; 3x social; 5–10x flash sales
5,000 RPSper server for simple APIs, at 70% utilization
30,000queries/s per database; Redis 100,000+ ops/s
20–30%extra for database indexes; replication usually 3x
Trade-off · Presenting estimates
DoDon't
Numbers"~12,000, call it 10K""12,453 per second"
TrafficDesign for peak, 2–3xDesign for the average
TimeApproximate, move onSpend over 5 minutes
ResultTie numbers to decisionsSkip the "so what"
  • Forgetting growth: 100 GB now can be 1 TB in a year at 10x growth.
  • Forgetting replication (500 GB × 3 = 1.5 TB) or that images make posts 100x bigger.
  • Mixing megabytes and megabits: MB/s × 8 = Mbps.

Part 4Networking Fundamentals for System Design

TCP guarantees, at a price. TCP gives reliable, ordered delivery with flow and congestion control, but the handshake costs 1 RTT before the first request and one lost packet blocks everything behind it.

UDP when late data is useless. No handshake, an 8-byte header, message boundaries kept, no reliability. Use it for real-time video, voice, gaming, DNS and as QUIC's base.

HTTP/1.1 → 2 → 3. HTTP/1.1 sends one request at a time per connection. HTTP/2 multiplexes streams and compresses headers over one TCP connection. HTTP/3 runs QUIC over UDP: a lost packet only blocks its own stream.

Reuse connections. Each new connection pays TCP and TLS handshakes and starts in slow start. Keep-alive and connection pools avoid that; short connections also pile up in TIME_WAIT and exhaust ephemeral ports.

Scaling WebSockets. Connections are stateful, so the load balancer needs stickiness, and users on different servers reach each other through a pub/sub backbone (Redis, Kafka). Use SSE for one-way server push.

1 RTTTCP handshake; TLS 1.3 adds 1, TLS 1.2 adds 2
~55 msminimum NYC–London RTT, set by light in fiber
0.5 · 1–2 · 100–200 mssame datacenter, cross-AZ, cross-continent
30,000 portsneeded at 500 connections/s × 60 s TIME_WAIT
Trade-off · gRPC vs REST
gRPCREST
FormatProtobuf, binaryJSON, text
Browser supportLimited (grpc-web)Native
StreamingFullLimited
Use forInternal microservicesPublic APIs, browsers
  • Opening a new connection per request instead of pooling: handshakes, slow start, port exhaustion.
  • WebSocket for request-response or one-way push, where HTTP or SSE is simpler.
  • Assuming HTTP/2 solved head-of-line blocking: it still rides one TCP connection.

Part 5Operating System Concepts for System Design

Processes isolate, threads share. A process owns its memory and file descriptors, so one crash kills only itself. Threads share the heap and descriptors with their own stacks: cheap to create and switch, but one crash kills them all.

Event loops scale connections. Thread-per-connection doesn't scale past ~10K connections. epoll registers descriptors once and returns only the ready ones, so one thread serves thousands (Node.js, nginx, Redis).

Context switches cost more than they look. Saving registers is cheap; the TLB flush, cold CPU caches and pipeline flush are not. Use async I/O, thread pools, batching and CPU affinity to switch less.

Write-ahead logging. Append the change to a sequential log and fsync it before touching data files; on a crash, replay the log. Sequential HDD writes run ~100 MB/s versus ~1 MB/s random.

Containers are namespaces plus cgroups. Namespaces isolate what a process sees (PID, network, mounts, users); cgroups limit what it uses (CPU quota, memory). Exceed the memory limit and the container is OOM killed.

1–10 μs vs 10–100 μscontext switch: threads vs processes
~1 MBstack per thread: 1M threads need 1 TB of stacks
1,024default file descriptor limit; each connection uses one
1.5–2xslower remote-node memory access on NUMA systems
Trade-off · Mutex vs semaphore vs RWLock
MutexSemaphoreRWLock
Lets inOne threadN threadsMany readers or one writer
OwnershipLocker unlocksNonePer lock mode
Use forShared dataPools, rate limitsRead-heavy data
  • Thread-per-connection for a million connections instead of an event loop.
  • Taking locks in different orders across threads: a deadlock waiting to happen.
  • Running a database that caches pages itself without O_DIRECT, so data is cached twice.

Part 6System Design Terminology & Theory

CAP is C or A during a partition. Partitions will happen, so P isn't optional. During one, a CP system refuses what it can't confirm (ZooKeeper, etcd); an AP system answers with possibly stale data (Cassandra, DNS).

PACELC. Even with no partition, strong consistency costs latency: synchronous replication waits for the slowest replica. DynamoDB and Cassandra are PA/EL; HBase is PC/EC.

Isolation levels. Read uncommitted allows dirty reads; read committed (PostgreSQL's default) allows non-repeatable reads; repeatable read (MySQL's default) allows phantoms; serializable allows none.

Consistency models. Linearizability respects real-time order; sequential keeps only each process's program order; causal keeps cause before effect (vector clocks); eventual only promises convergence.

Delivery semantics. At-most-once may lose messages; at-least-once may duplicate them, so consumers must be idempotent; exactly-once needs idempotent producers and consumers, or transactional messaging.

Error budgets. A 99.9% SLO allows 43.2 minutes of downtime in a 30-day month. Budget left: ship fast. Budget gone: freeze features and fix reliability. Keep the SLA looser than the SLO.

R + W > Nquorum overlap, e.g. N=3, W=2, R=2
3f + 1nodes to tolerate f Byzantine failures
43.2 minmonthly error budget at 99.9%
~10 msan fsync on HDD; group commit batches them
Trade-off · ACID vs BASE
ACIDBASE
ConsistencyStrongEventual
ApproachPessimistic: lock earlyOptimistic: resolve later
ScalingMainly verticalHorizontal
Use forPayments, inventory, accountsFeeds, catalogs, sessions
  • "Pick 2 of 3" in CAP: partition tolerance is a given, not a choice.
  • Assuming exactly-once delivery is free instead of making consumers idempotent.
  • Saga compensations that aren't idempotent: they may run more than once.

Part 7API Design for System Design

Resources, not verbs. Model things as plural nouns with a few standard methods: Get, List, Create, Update, Delete. A real verb stays rare and attached to a resource: POST /v1/orders/{id}:cancel.

Paginate with cursors from day one. Adding pagination later breaks clients. Keyset on (sort key, unique ID) with an opaque token costs the same on every page; offset walks every skipped row and duplicates or skips rows under writes.

Additive changes only. Within a version, add endpoints, optional request fields and response fields. Renames, removals, type changes, new required fields and changed defaults break clients. Clients ignore unknown fields.

Idempotency keys on POST. The client sends one key per logical operation and reuses it on every retry. A repeat returns the original response; the same key with a different body is an error.

Errors are a contract. Clients branch on a stable code; people read the message. RFC 9457 problem details, plus the field and whether to retry. One shape for every error, including the gateway's 429s.

Slow work becomes a resource. Return 202 with a status resource to poll, whose terminal states never change. Servers also get a webhook, mobile apps a push. Big results are a link to object storage.

100max page size: Stripe limit, most GitHub per_page
24 hoursbefore Stripe may prune an idempotency key
5,000 an hourGitHub REST limit per user; 60 unauthenticated
24 monthsGitHub keeps supporting the previous version
Trade-off · Offset vs cursor pagination
OffsetCursor
CostGrows with depthConstant per page
Concurrent writesDuplicates and gapsStable
Jump to page 50YesNo
FitsSmall bounded listsFeeds, histories, public APIs
  • POSTs without an idempotency key: every timeout on an order or payment can become a duplicate.
  • Renaming or retyping a field inside a version instead of adding alongside.
  • Slow work inside the request instead of 202 and an operation.

Part 8Databases in Depth

A commit is one sequential write. Every change is appended to the WAL first; a commit is durable once its log record is flushed, while changed pages are written later. Group commit lets one fsync cover many transactions.

Composite index order. Equality columns first, then the one range or sort column. (user_id, created_at, id) reads 20 adjacent entries for a user's latest orders; INCLUDE the payload to make it covering.

Lost update and write skew. Read-then-write code loses updates on both PostgreSQL's and InnoDB's defaults: use a guarded atomic update or FOR UPDATE. Write skew needs Serializable or a constraint like UNIQUE (customer_id, coupon_code).

Where MVCC keeps old versions. PostgreSQL writes a new tuple in the heap and VACUUM removes the old one. InnoDB updates in place and keeps old versions in undo, which purge discards. A long transaction blocks both.

Optimistic concurrency. Each row has a version; the update runs WHERE version = seen. Zero rows means someone changed it: reload and decide again. It spans a user's think time, and maps to ETag and 412.

Time-ordered IDs. UUIDv4 inserts at random index leaves, so the whole index becomes the working set. UUIDv7 and Snowflake IDs sort by time and keep inserts at the index's right edge.

8 kB · 16 KBpage size: PostgreSQL, InnoDB default
4B-tree depth for a billion rows, whatever the key
~1,000commits a second, each waiting for its own 1 ms flush
25% of RAMsuggested PostgreSQL shared_buffers, dedicated server
Trade-off · B-tree vs LSM-tree
B-treeLSM-tree
WritesIn place, random, on commit pathAppends, merged in background
Reads~1 disk read, predictableSeveral files; scans cost more
Best forRead-heavy OLTP, rangesMessages, events, metrics
ExamplesPostgreSQL, InnoDBRocksDB, Cassandra, ScyllaDB
  • Trusting the default isolation level with read-then-write code: neither prevents lost updates.
  • An index for every slow query. Each taxes every write; read EXPLAIN first.
  • Long transactions on the primary: they block vacuum and purge. Run reports on a replica.