Skip to the chapter
←System DesignGGroundworkSDSystem Design
System Design/Beginner/B2
2 / 36 written chapters
/

The cover
  1. B1The mental model
  2. B2Client-server basics
  3. B3Vertical vs horizontal
  4. B4Databases in design
  5. B5Caching fundamentals
  6. B6APIs & communication
  7. B7Walkthrough: URL shortener
  1. I1Load balancing in depth
  2. I2CDNs
  3. I3Message queues & async
  4. I4Consistency models
  5. I5Replication
  6. I6Rate limiting & throttling
  7. I7Designing for availability
  8. I8Storage systems
  9. I9Search systems
  10. I10Microservices
  11. I11Security basics
  12. I12Walkthrough: feed/chat
  13. I13Walkthrough: notifications
  1. A1CAP theorem in depth
  2. A2Transactions and isolation
  3. A3Storage engines
  4. A4Sharding at scale
  5. A5Time, ordering and IDs
  6. A6Distributed consensus
  7. A7Batch & stream processing
  8. A8Fault tolerance
  9. A9Observability at scale
  10. A10Release safety
  11. A11Capacity estimation
  12. A12Case studies
  13. A13Walkthrough: key-value store
  14. A14Walkthrough: web crawler
  15. A15Walkthrough: payments
  16. A16Tradeoff thinking

SDB2 · Part 1 · Beginner

Client-server basics

A senior candidate can narrate everything between the keypress and the pixel — and knows what each hop costs in milliseconds.

18 min read2 diagrams8 sections0 exercises
2 of 36

In this chapter

  • The one question that separates levels: "what happens when I hit enter?"
  • DNS: four lookups you hope never to make
  • TCP and TLS: the cost of a cold connection
  • HTTP/1.1 vs HTTP/2 vs HTTP/3, at the level that changes a design
  • Load balancer, reverse proxy, API gateway

and 3 more

about 18 min
08On this page
  1. The one question that separates levels: "what happens when I hit enter?"
  2. DNS: four lookups you hope never to make
  3. TCP and TLS: the cost of a cold connection
  4. HTTP/1.1 vs HTTP/2 vs HTTP/3, at the level that changes a design
  5. Load balancer, reverse proxy, API gateway
  6. Statelessness is the property everything else is built on
  7. Numbers every engineer should know
  8. Recognizing it in an unseen problem

The one question that separates levels: "what happens when I hit enter?"

This looks like a trivia question and is actually a depth probe. Anyone can say "the browser sends a request to the server." The signal is in whether you can name each hop, say roughly what it costs, and identify which hops you get to influence as a designer. Every scaling technique in later chapters — caching, load balancing, CDNs, replicas — is an intervention at one specific point on this path. If the path is fuzzy, the interventions sound arbitrary.

browser recursive resolver authoritative NS load balancer (TLS terminates here) app server 1 stateless app server 2 stateless cache 0.5 ms, 90% hit primary DB 5-20 ms, hard to scale 1. DNS: 0 ms warm, 20-120 ms cold 2. TCP + TLS: 2-3 RTT Everything left of the load balancer you influence with DNS and connection reuse. Everything right of it you influence with statelessness, caching, and how rarely you touch the red box.
The red box is the one component in this picture that is genuinely hard to scale. Most of system design is a campaign to talk to it less often.

DNS: four lookups you hope never to make

The browser needs an IP address before it can open a socket. It asks its configured recursive resolver (your ISP's, or a public one like 8.8.8.8), and that resolver is the component that does the actual walking: it asks a root nameserver who handles .com, asks that TLD server who is authoritative for example.com, and asks the authoritative nameserver for the record. Each step is a network round trip, which is why a genuinely cold resolution can cost 100 ms or more, and why in practice it costs zero — every layer caches.

Caching is governed by the record's TTL. A 60-second TTL means fast failover and heavy query load on your nameservers; a 24-hour TTL means the opposite. The critical property for design: the TTL is a hint, not a contract. Resolvers clamp it, operating systems cache on top of it, and browsers keep their own cache for a minute or two regardless. If you plan to move traffic by changing a DNS record, assume a long tail of clients keeps using the old answer for hours.

The record types you will actually name in a design are few: A and AAAA map a name to an IPv4 or IPv6 address, CNAME aliases one name to another (not allowed at the zone apex, which is why providers invent "ALIAS" records), NS delegates a zone, MX routes mail, and TXT carries verification and policy strings. When a name returns both A and AAAA records, clients using Happy Eyeballs (RFC 8305) start IPv6 first and, if it has not connected after a short delay (RFC 8305 recommends 250 ms), start IPv4 and keep whichever completes first, so a broken IPv6 path costs a fraction of a second rather than a full timeout.

DNS routing strategyMechanismReach for this when…
Multiple A records (round robin) Return several IPs; clients pick roughly at random You need crude spread across a handful of static endpoints and nothing better is available
Weighted records Return IP A 95% of the time, IP B 5% Canary deploys and gradual migrations between stacks or providers
GeoDNS / latency-based Answer depends on the resolver's location or measured latency Multi-region: send European users to the European stack, so each round trip drops from roughly 80-100 ms to tens of milliseconds or less (a cold connection makes several of them)
Health-checked failover Provider probes endpoints and withdraws dead records Regional disaster recovery — accept that failover takes TTL plus stubborn-cache time
Anycast One IP announced from many locations; BGP routes each client to the topologically nearest announcement What CDNs and large services actually use — no client caching problem, and failover is a BGP route withdrawal rather than a TTL expiry. "Nearest" means nearest in network terms, not geographic distance, and route convergence can take from seconds to minutes. A routing shift can also break long-lived TCP connections mid-flight. Requires network-level infrastructure

So DNS is a load balancer, but a bad one: it balances resolvers rather than requests, it can't see that a server is at 99% CPU, it can't do per-request decisions, and its failover is measured in minutes. It is the right tool for coarse geographic steering and the wrong tool for anything reactive.

⚠ "We'll just lower the TTL to 30 seconds and fail over" This is the most common wrong answer about DNS in an interview. Aggressive TTLs help, but a meaningful fraction of clients — corporate resolvers, some mobile stacks, anything with a broken cache — will keep hammering the dead IP well past it. If failover must be fast, the address must stay the same: anycast, a virtual IP that moves, or a load balancer in front.

TCP and TLS: the cost of a cold connection

With an IP in hand the client still cannot send a byte of HTTP. TCP needs a three-way handshake (one round trip before the client can send data), and TLS needs its own negotiation on top: two round trips in TLS 1.2, one in TLS 1.3, and zero on resumption if you accept the replay risk of 0-RTT data.

client server SYN SYN-ACK ACK + ClientHello (key share) ServerHello + certificate + Finished Finished + GET /feed 200 OK — first byte of HTML 1 RTT TCP 1 RTT TLS 1.3 1 RTT HTTP Three round trips before any content. Same datacenter: ~1.5 ms. New York to Sydney at 200 ms RTT: 400 ms of handshake, then the request.
Round trips, not bandwidth, dominate first-byte latency on long paths. Every technique that helps — keep-alive, TLS session resumption, QUIC, terminating TLS at an edge PoP — is a way to delete one of these arrows.

Two design consequences follow directly. First, connection reuse is not an optimisation, it's the baseline: HTTP keep-alive, connection pools in your service-to-service clients, and pooled database connections all exist to amortise this cost. A service that opens a fresh TLS connection per request has added several RTTs and a public-key operation to every call. A fresh TCP connection is also slow in a second way: congestion control starts it in slow start, with an initial window of about 10 segments (roughly 14 KB, RFC 6928), so a response bigger than that needs extra round trips to ramp up even after the handshakes. A warm, reused connection has already ramped. Second, terminating TLS close to the user matters enormously. A CDN PoP 10 ms from the user absorbs the handshake round trips locally and reuses a warm connection back to origin, which is often a bigger win than caching the content itself.

HTTP/1.1 vs HTTP/2 vs HTTP/3, at the level that changes a design

HTTP/1.1HTTP/2HTTP/3
TransportTCP, one request in flight per connectionTCP, many streams multiplexed on one connectionQUIC over UDP, streams are independent
Head-of-line blockingAt the HTTP layer — a slow response blocks the connectionFixed at HTTP layer, still present at TCP layer: one lost packet stalls every streamGone — a lost packet stalls only its own stream
HandshakeTCP + TLS, 2-3 RTTSame1 RTT combined, 0-RTT on resumption
HeadersPlain text, repeated in full every requestHPACK compressionQPACK compression
Connection migrationBreaks on network changeBreaks on network changeSurvives a Wi-Fi to cellular switch via connection ID
Reach for this when…Simple internal service-to-service; still the default for many proxies to originDefault for browser traffic and gRPC; many small resources over one connectionLossy or mobile networks, and latency-sensitive global traffic — the win grows with packet loss

The practical fallout you should be able to state: because HTTP/1.1 allows one outstanding request per connection, browsers open about six connections per origin, and the old trick of "domain sharding" existed to buy more. On HTTP/2 that trick is actively harmful — it defeats multiplexing and header compression and multiplies handshakes. And HTTP/2's remaining weakness is real: multiplexing many streams over one TCP connection means one dropped packet stalls all of them, which is exactly the case QUIC was built to fix.

Say it like this → "Browser to edge I'd run HTTP/3 with HTTP/2 fallback — our users are mobile and packet loss is where QUIC pays. Edge to origin I'd keep long-lived HTTP/2 connections so the origin isn't paying handshake cost per request. Internally, gRPC over HTTP/2 for the streaming and header compression."

Load balancer, reverse proxy, API gateway

These overlap enough that candidates use them interchangeably and get caught. A reverse proxy is any server that accepts a client connection and makes its own request to a backend on the client's behalf; a load balancer is a reverse proxy whose defining job is distributing across many backends; an API gateway is an L7 reverse proxy that additionally owns cross-cutting concerns — authentication, rate limiting, request shaping, per-route policy. One box often does all three.

L4 (transport)L7 (application)
SeesIPs, ports, TCP connectionsFull HTTP: method, path, headers, cookies, body
Can doConnection-level distribution, extremely high throughput, near-zero added latency. Passes TLS through untouched, or terminates it (for example an AWS Network Load Balancer TLS listener) without ever seeing HTTPPath and header routing, retries, rate limiting, request rewriting, sticky sessions, per-request balancing. To read HTTP at all it must terminate TLS (or terminate and re-encrypt)
CostCannot see individual requests or per-request errors on a long-lived connectionMore CPU, added latency (typically well under a millisecond), and it must hold the TLS keys
Reach for this when…Raw TCP services, databases, extreme packet rates, or you want the backend to see the real client TLSEssentially all HTTP traffic — the routing and observability are worth the overhead

Beyond distribution, the load balancer is where three other things live, and naming them unprompted is a strong signal: health checks (active probes plus passive outlier ejection when a backend starts erroring), TLS termination, and the balancing algorithm itself. Round robin is fine when every request costs the same; least-outstanding-requests is materially better when they don't, because it routes away from a backend that has quietly become slow. Consistent hashing is the choice when backends hold a warm per-key cache and you want the same key to land on the same node.

⚠ Don't draw one load balancer box and move on A single load balancer is a single point of failure, and the interviewer will ask. The real answer is a pair or a fleet behind a floating virtual IP or an anycast address, health-checked, with the DNS record pointing at the address rather than any individual machine. It is also worth saying that a managed L7 balancer scales itself, but its connection and rules limits are real quotas you should know exist.

Statelessness is the property everything else is built on

A stateless app server is one where any request can be served correctly by any instance, because no request depends on memory left behind by a previous request on that same box. Every request carries or fetches everything it needs. That single property is what makes horizontal scaling, rolling deploys, autoscaling, and instance failure all boring — you can add, remove, or kill a server without anyone noticing.

Statelessness does not mean the system has no state. It means the state has been moved somewhere purpose-built: a database, a cache, a blob store, or the client itself. The interview question is always where did you put it.

Where session state livesCostReach for this when…
In app server memory + sticky sessions Losing a node logs users out; deploys are disruptive; load skews toward whichever node holds the busy users; autoscaling barely helps Almost never in a new design — know it mainly so you can explain why you rejected it
Shared session store (Redis, Memcached) One extra network hop (~0.5 ms) per request; the store becomes a dependency you must make highly available You need server-side revocation, large session payloads, or session data that changes mid-session
Signed token in a cookie (JWT and friends) No lookup at all, but revocation is genuinely hard and every request pays the token size in bytes Read-mostly identity claims with short expiry, plus a refresh token you can revoke server-side
Say it like this → "The app tier is stateless — session lives in Redis, uploads go straight to object storage, and anything in process memory is a cache that can be dropped. That means the load balancer can use plain least-outstanding-requests, I can autoscale on CPU, and losing an instance costs us the in-flight requests only."

Numbers every engineer should know

You will be asked to justify a latency budget, and the justification has to be built from components. Memorise the orders of magnitude, not the digits. The single most useful mental jump is that each of these tiers is somewhere between 10x and 1,000x slower than the last: nanoseconds in cache and memory (about 1 ns in L1, about 100 ns for main memory), tens of microseconds on SSD, about half a millisecond for a datacenter round trip, and hundreds of milliseconds across the planet. Going from memory to a same-datacenter round trip alone is a factor of about 5,000.

These are rounded planning numbers, not measurements. The original table attributed to Jeff Dean (mutex 25 ns, 1 MB read from memory 250 µs, disk seek 10 ms) describes hardware of roughly that era; Colin Scott's interactive page extrapolates it to today and is where the optimistic 3 µs figure for a sequential memory read comes from. Where the two disagree this table gives a range.

OperationTimeWhat it means for you
L1 cache reference~1 nsFree; never a design consideration
Branch mispredict~3 nsFree
Mutex lock/unlock~20 nsContention, not the lock itself, is what hurts
Main memory reference~100 nsAn in-process cache hit is thousands of times faster than a network cache hit
Read 1 MB sequentially from memory~30-100 µs in practice (classic table: 250 µs; 2020 extrapolation: 3 µs)Serialisation and copying cost as much as the read itself
SSD random read~16-100 µsA cache miss to local NVMe is survivable; to a remote DB it is not
Round trip in the same datacenter~0.5 msEvery internal service hop costs this at minimum — this is why chatty microservices die
Redis GET over the network~0.2-1 msDominated by the round trip, not by Redis
Simple indexed DB query, warm~1-10 msYour typical read-path floor
HDD seek~2-10 msWhy random I/O on spinning disks shaped a generation of storage design
Cross-region RTT (US East to US West)~60-70 msOne synchronous cross-country call eats most of a 100 ms budget, and two blow it
Cross-continent RTT (US East to Western Europe)~70-90 ms (New York to London is about 65-70)Speed of light in fibre, not an engineering problem you can optimise
Cross-planet RTT (US East to Singapore or India, New York to Sydney)~200-230 msMulti-region read-local architecture is mandatory, not a nice-to-have
The budget arithmetic that wins arguments For a 200 ms p99 page load with a user 80 ms away: 80 ms is gone to the network round trip before your code runs, leaving about 120 ms. That assumes a warm connection: on a cold one every handshake round trip costs another 80 ms and the budget is gone before the server runs (see the dry run below). Those 120 ms of server time are enough for one cache hit plus one database query, or about five sequential internal service calls if each does around 20 ms of real work. Sequential dependencies, not slow code, are what usually eat the budget.

Note that the speed of light in fibre is about 200,000 km/s, so New York to London (5,600 km) has a physical floor near 55 ms round trip. Measured paths on that route run only about 15% above it (around 64 ms); less direct routes run further above their floor. When you say "we cannot make this call synchronous across regions", you are citing physics, and interviewers recognise the difference between that and an opinion.

Dry run: a 200 ms page-load budget for a user 80 ms away

HopCostRunning totalBudget left of 200 ms
Cold TCP handshake (1 RTT)80 ms80 ms120 ms
TLS 1.3 handshake (1 RTT)80 ms160 ms40 ms
HTTP request + response (1 RTT)80 ms240 ms-40 ms — budget already blown, before a line of server code ran
Same request, warm connection: HTTP request + response only (1 RTT)80 ms80 ms120 ms
Server does one cache hit (~0.5 ms) + one indexed DB query (~5 ms)~5.5 ms85.5 ms~114.5 ms to spare

Three round trips for a cold connection cost more than the entire 200 ms budget by themselves — the server never gets to run. The identical request on a warm, reused connection has 120 ms of budget left before the server does anything, which is why connection reuse and edge TLS termination are not tuning knobs but the difference between meeting the budget and missing it entirely.

Recognizing it in an unseen problem

  • Any prompt with a latency target ("under 200 ms p99") is asking you to build a budget out of the table above — say where the milliseconds go before proposing optimisations
  • "Users are global" means the physics number, ~100-250 ms RTT, is now in every request; the design answer is edge termination and read-local replicas, not faster servers
  • If a component holds per-user state in memory, the interviewer will ask what happens when it restarts — decide up front whether that state is durable, reconstructible, or genuinely disposable
  • "How would you do a zero-downtime deploy / autoscale this?" is a statelessness question wearing a costume
  • DNS is the answer for coarse geographic routing and gradual migrations; it is never the answer for fast failover or per-request balancing — an interviewer probing failover wants anycast or a floating VIP
  • Distinguish bandwidth problems from round-trip problems: large media is a bandwidth and CDN problem, chatty APIs are a round-trip problem, and they have completely different fixes
Before you move on
  • Can you name each hop in "what happens when I hit enter" and roughly what it costs in milliseconds?
  • Can you explain why lowering the DNS TTL alone doesn't give you fast failover, and what actually does?
  • Can you compute how many round trips a cold TLS 1.3 connection costs before the first HTTP byte, and explain why connection reuse matters?
  • Can you distinguish an L4 from an L7 load balancer, say when you'd choose each, and explain why an L7 balancer always terminates TLS while an L4 one only may?
  • Can you explain what "stateless" means for an app server and where you'd move the state instead?
Sources and further reading
  • RFC 8446: TLS 1.3 — the 1-RTT handshake and the replay caveats of 0-RTT data
  • RFC 9000: QUIC — combined transport and crypto handshake, and connection migration by connection ID
  • RFC 9114: HTTP/3 — how HTTP maps onto QUIC streams
  • RFC 9293: TCP — the current TCP specification, including required congestion control
  • RFC 6928: increasing TCP's initial window — why a fresh connection starts at about 10 segments
  • RFC 8305: Happy Eyeballs version 2 — racing IPv6 and IPv4 connection attempts
  • AWS: Network Load Balancer TLS listeners — an L4 balancer that can terminate TLS
  • Latency numbers every programmer should know — the classic table usually attributed to Jeff Dean (100 ns memory, 250 µs per MB from memory, 10 ms disk seek)
  • Interactive latency numbers by year — the extrapolated latency table, labelled as estimates
  • New York to London round-trip measurements — roughly 64 ms measured against a 55 ms fibre floor

Claims in this chapter were checked against these sources in October 2026. Figures marked "planning figure" are rules of thumb, not guarantees.

✓Practise

5 questions drawn from 8, scored out of 5. This is practice: it runs in your browser, saves nothing and does not change what you have marked read.

B2

Finished reading?

0 of 36 chapters read in this series

→Next stop

  1. B1Previous · B1What system design interviews test
  2. B2you are here
  3. Next · B3Scaling: vertical vs horizontalBuy a bigger box or buy more boxes — and one modern box is far bigger than the candidate who instantly reaches for a cluster believes.16 min read

01On this page

8 sections · 0%

  1. 01The one question that separates levels: "what happens when I hit enter?"
  2. 02DNS: four lookups you hope never to make
  3. 03TCP and TLS: the cost of a cold connection
  4. 04HTTP/1.1 vs HTTP/2 vs HTTP/3, at the level that changes a design
  5. 05Load balancer, reverse proxy, API gateway
  6. 06Statelessness is the property everything else is built on
  7. 07Numbers every engineer should know
  8. 08Recognizing it in an unseen problem

[] chapters · t top