System Design Networking
Network Protocols
First tokens on chatgpt.com should stream before the page feels stuck. To the user it feels like one action. Under the hood, the browser has to find the right server, open a path, encrypt the conversation, send the request, and keep receiving response chunks without making the page feel stuck.
Network protocols are the agreements that make that possible. Good system design is not memorizing every protocol name; it is knowing which agreement matters when search feels slow, a chat stream pauses, a mobile network drops packets, or a secure request must not be tampered with.
What happens first?
Find the server behind the name.
/
Open a path and handle packet loss.
Encrypt the conversation.
Send the message and stream response chunks.
One tap becomes many conversations
The user sees one search box or one chat input. Underneath, the client first asks, "Where is chatgpt.com or google.com?" answers with an . Then the client asks the server, "Can we talk?", , or another transport decides how that conversation starts and how lost packets are handled.
Before business data leaves the device, proves the server identity and encrypts the channel. Only after those setup steps does carry the actual meaning: method, path, headers, body, status code, caching rules, streaming behavior, and retry behavior.
That is why protocol choice appears in interviews. A search page needs low first-byte latency and aggressive caching. A chat product cares about a fast connection and smooth token streaming. A multiplayer game or video call may prefer dropping stale data over waiting for perfect delivery.
User action
Search query or ChatGPT message
DNS finds the place
Name becomes an IP address
Transport opens the path
TCP stream or QUIC over UDP
TLS makes it private
Encryption + server identity
HTTP carries intent
GET, POST, headers, streaming chunks
Routers move packets
Across Wi-Fi, ISPs, CDNs, regions
Server reverses the stack
Bytes become application work
How to choose a protocol
1. Is every message important? For payments, orders, logins, and database writes, losing data is not acceptable. Use over because it delivers data reliably and in order.
2. Is old data still useful? In a video call, online game, or live cursor movement, a packet from 200 milliseconds ago may already be useless. In those cases, it can be better to skip stale data than to wait for perfect delivery.
3. Will real users be able to use it? Browsers, mobile networks, office firewalls, old apps, and CDNs may block or limit some protocols. The best protocol is the one that works reliably for the clients you actually have.
Simple rule of thumb
Start with . It is safe, widely supported, and correct for most APIs and websites. Change the protocol only when the product needs something specific: chat needs , video calls need , internal services may need , and mobile-heavy apps may benefit from .
In simple terms: do not pick a protocol because it sounds advanced. Pick it because it solves a real user problem.
Networking layers in simple language
Encapsulation means that each layer wraps the information from the layer above it. An HTTP request becomes bytes in a TCP stream; TCP segments carry portions of those bytes, IP packets carry the segments, and link-layer frames carry packets across each local hop. The receiving side removes those wrappers in reverse. A router normally forwards using IP information without interpreting your application’s JSON.
The layers provide different promises. IP attempts to move packets to a destination. TCP reconstructs an ordered byte stream using sequence numbers, acknowledgments, and retransmission. HTTP gives those bytes application meaning. None of those steps alone proves that a database transaction committed, so an application acknowledgment and a retry strategy are still necessary.
Think of layers as a way to follow one request from your app all the way down to signals on a wire or radio. When something breaks, layers help you ask: is this an app problem, a delivery problem, or a routing problem?
What the product wants to do: search, chat, upload, pay, stream.
How data is formatted, compressed, or encrypted before it is sent.
How a conversation is started, kept alive, resumed, or closed.
How bytes are delivered: reliably, quickly, in order, or with some loss allowed.
How packets find the right machine across many networks.
How data moves across the next local hop, such as your Wi-Fi router.
The actual signal: electricity, light, or radio waves.
What to focus on
For most system design problems, focus on three things: where the request goes (IP and routing), how data is delivered (TCP, UDP, QUIC), and what the app is saying (DNS, HTTP, WebSockets, gRPC). You usually do not need to discuss cables or hardware unless the problem is about data centers or networking infrastructure.
Simple shortcut
If seven layers feel too much, remember this simpler stack: app sends the request, transport delivers it, network routes it, and link/physical moves it across the next cable, Wi-Fi, or cellular hop.
What actually happens across the layers
L3: IP
This layer decides where packets should go. A public IP can be reached from the internet. A private IP usually works only inside your home network, office network, or cloud VPC.
Ask yourself: what address does the user connect to, and does a load balancer forward it somewhere else?
L4: TCP / UDP / QUIC
This layer decides how data is delivered. TCP provides an ordered byte stream by recovering missing data while the connection remains viable. UDP supplies datagrams without built-in delivery or ordering guarantees. QUIC builds reliable streams and congestion control over UDP, so using UDP underneath does not mean an application accepts lost data.
Ask yourself: is it more important to be reliable, or to stay realtime even if a few packets are lost?
L7: App protocols
This is the layer your product usually talks about. DNS finds the server. HTTP loads pages and APIs. WebSockets keep a chat-style connection open. WebRTC helps with calls and realtime media.
Ask yourself: is this a normal request, a live chat stream, or a realtime call?
IPv4 vs IPv6: how devices get addresses
Every device needs an address so packets know where to go. IPv4 is the older, still-common system. IPv6 is the newer one with far more addresses.
IPv4
Address size
4 bytes (32 bits)
192.168.1.1
- • ~4.3 billion total addresses
- • Dotted decimal notation
- • Min header: 20 bytes
- • Has checksum (slower router processing)
IPv6
Address size
16 bytes (128 bits)
2001:0db8:85a3::8a2e:0370:7334
- • 340 undecillion addresses (3.4 × 10³⁸)
- • Hexadecimal colon notation
- • Fixed header: 40 bytes
- • No checksum (faster router processing)
Why did we need IPv6?
1. IPv4 exhaustion
4.3 billion addresses sounded like a lot in 1981. Today, a single household may have 20+ connected devices: phones, laptops, TVs, smart bulbs, and thermostats. IANA allocated the last IPv4 blocks in 2011.
2. NAT is a band-aid
We stretched IPv4 with , where many devices share one public IP. But NAT can break peer-to-peer connections, complicate gaming or voice calls, and add extra network work. It is a workaround, not a clean solution.
3. IoT explosion
Sensors, cameras, cars, industrial machines, and smart home devices all need network identities. IPv6 gives enough address space for this growth without forcing everything through shared IPv4 addresses.
| Feature | IPv4 | IPv6 |
|---|---|---|
| Address size | 32 bits (4 bytes) | 128 bits (16 bytes) |
| Total addresses | ~4.3 billion | ~3.4 × 10³⁸ |
| Header size | 20-60 bytes (variable) | 40 bytes (fixed) |
| NAT required? | Often yes | No: end-to-end |
| Built-in security | Optional (IPSec) | Mandatory (IPSec) |
| Example | 192.168.1.1 | 2001:db8::1 |
Routers, IP addresses, and load balancers
Routers read the destination on each packet and choose the next step. A public IP is like a street address on the internet. A private IP is like a room number inside one building.
How routers work
Packet forwarding: A router reads the destination and sends the packet to the next network.
: This is the router's map. It tells the router which direction to send packets for each IP range.
Next-hop decision: A router does not plan the full journey. It only chooses the next step, then the next router continues from there.
: This is a safety counter. Every router reduces it by one. If it reaches zero, the packet is dropped so it cannot loop forever.
Public vs private IP
Public IP. Your internet address
This address can be reached from the internet. Your ISP or cloud provider assigns it. Example: 203.0.113.42
Private IP: address inside a network
This address works inside your home, office, or cloud network. The public internet cannot directly reach it. Your router uses to translate between private and public addresses.
Common private IP ranges
10.0.0.0/8: 16M addresses (large corps)
172.16.0.0/12: 1M addresses (medium)
192.168.0.0/16: 65K addresses (home)
How your request reaches a server
Load balancers: traffic directors
A load balancer exposes one and spreads incoming traffic across many private backend servers. Clients do not need to know which server handled the request.
Routes using IP and port. It is fast because it does not inspect HTTP details. Example: cloud network load balancer.
Routes using HTTP details like path, headers, cookies, or host. It is smarter, but does more work per request.
Why VIP matters
DNS can point to one stable VIP while the platform adds or removes backend servers behind it. Scale changes without changing what users connect to.
Quick words you will see again
- : where a device or service lives on the network.
- : which app on that device should receive the data.
- : careful delivery. Data arrives in order, and missing pieces are resent.
- : how much data TCP is allowed to send at once before waiting for replies.
- : fast delivery with fewer promises. Some packets may be late or lost.
- : the lock on the connection. It encrypts data and helps prove the server is real.
How a TCP conversation starts and ends
Before useful data can move, spends a short hello exchange so both sides agree they are ready. When the conversation is over, each side says goodbye carefully so nothing is lost mid-sentence. That setup cost is the price of reliability.
SYN: "Can we talk?"
The client starts the conversation and proposes a starting number so both sides can track the bytes that follow.
SYN-ACK: "Yes, I am ready too."
The server answers yes, confirms the client's hello, and shares its own starting number.
ACK: "Perfect, let's begin."
The client confirms the server's hello. Now both sides are lined up and useful data can flow.
FIN: "I am done sending."
One side says it has finished speaking. It can still listen for anything left to arrive.
ACK: "Got it."
The other side confirms. The conversation is half closed: one direction is finished, the other may still send.
FIN: "I am done too."
After sending anything left, the second side also says goodbye.
ACK + TIME_WAIT: "Okay, I will wait a moment."
The first side confirms the goodbye and waits briefly so late packets do not confuse a brand-new connection that reuses the same numbers.
Why new connections feel slow
Every brand-new conversation pays a hello tax before useful data starts. Nearby servers feel this less. Distant users feel it a lot:
Same datacenter
~0.75 ms
0.5ms RTT × 1.5 = 0.75ms
Same region (US-East)
~30 ms
20ms RTT × 1.5 = 30ms
Cross-continent (US→EU)
~150 ms
100ms RTT × 1.5 = 150ms
A simple web request, end to end
One browser click feels like a single GET. Underneath, it is a short story: find the address, say hello, exchange the HTTP request and response, then say goodbye. Many packets hide behind one conceptual request.
Read the diagram definition
sequenceDiagram
autonumber
participant Browser
participant DNS
participant Server
Browser->>DNS: Resolve example.com
DNS-->>Browser: Destination IP
Browser->>Server: SYN
Server-->>Browser: SYN-ACK
Browser->>Server: ACK (TCP ready)
Browser->>Server: HTTP request (GET / path, headers)
Server-->>Browser: HTTP response (status, headers, body)
Browser->>Server: FIN
Server-->>Browser: ACK
Server->>Browser: FIN
Browser-->>Server: ACK (connection closed)What your app sees
An ordered stream of bytes. TCP handles missing pieces and reordering so you can focus on request and response logic.
One click, many packets
DNS, the TCP hello, HTTP pieces, acknowledgements, and goodbye steps can easily become dozens of packets.
Why connections cost
Each live session uses memory and CPU. A fresh hello adds wait time before useful data. Idle connections still hold resources.
Reuse when you can
Keep-alive reuses the same pipe for later requests. HTTP/2 can share many requests on one connection instead of opening several.
How TCP learns a safe sending speed
The internet is shared. If every app blasts data as fast as possible, routers overflow and everyone slows down. tries to find a safe speed: send a bit more when the path looks healthy, and back off when the network starts struggling.
Why it exists: links and routers have limited room. TCP keeps adjusting its send rate so one connection does not flood the path.
The main knob is : the congestion window. Think of it as "how many bytes may be in flight before I wait for replies."
Two useful words: MSS is roughly the biggest useful packet chunk on this path. is the round-trip time for a send and its reply.
Classic TCP: start carefully, then grow gently
Imagine turning on a tap slowly. TCP begins carefully, speeds up while replies look healthy, then grows more gently once it thinks it is near the limit.
- Slow start: begin with a small send window so you do not flood a weak path. If replies keep arriving, TCP ramps up quickly.
- Congestion avoidance: after a threshold, growth becomes careful. TCP tops off the path instead of doubling again and again.
- On trouble: if packets are lost, classic TCP treats that as "I was too fast" and cuts its send window sharply, then climbs again.
Phase 1: Slow start
cwndstarts small (often ~10 MSS today; older textbooks often assume 1 MSS).- While ACKs look healthy, cwnd ramps fast: about doubles per RTT in simple Reno sketches.
Phase 2: Congestion avoidance (past ssthresh)
- Growth becomes cautious: about +1 MSS per RTT in the textbook Reno picture.
- You are "topping off" the pipe instead of aggressively probing.
On loss: multiplicative decrease (classic view)
Loss is read as "you exceeded capacity". So cwnd is cut sharply (for example cwnd := cwnd / 2 in simple sketches) before cautiously growing again.
: measure the path, do not only react to loss
Classic often assumes "a lost packet means the path is full." On mobile networks and busy links, that guess can be wrong, so the connection stays slower than it needs to be.
tries a different story. It estimates how fast the path can really deliver data and how long a healthy should take, then paces sends near that speed instead of waiting for packets to disappear.
Loss-based TCP (Reno-style intuition)
"If packets disappear, I was too aggressive → slash cwnd."
BBR (high-level intuition)
"Estimate max sustainable delivery rate and baseline RTT; pace sends near the bottleneck and avoid building giant standing queues."
TCP: the careful default for most traffic
Most of the internet prefers because missing data is usually worse than waiting a little. If every byte must arrive in order, TCP is the usual starting point.
Where you see TCP every day
Web (HTTP/HTTPS)
Email (SMTP/IMAP)
File transfer (FTP/SFTP)
Databases (MySQL, Postgres)
SSH / Remote access
APIs (REST, gRPC)
Chat (WebSocket)
Payments (TLS)
If your app needs every byte to arrive, in order, start with . That is why it carries most internet traffic, including , , and .
What reliability costs
Speed takes time to warm up
A new connection does not instantly use the full path. TCP starts carefully and ramps up while replies look healthy.
Waiting before the first byte
The hello and steps can take a few . Also, one lost packet can pause the whole stream until that piece is resent.
What TCP does not promise
TCP also does not preserve application message boundaries. If an application writes two messages, a receiver may read them together or in several pieces. Protocols therefore need framing, such as a length prefix, delimiters, or an existing HTTP message format. A TCP acknowledgment confirms receipt by the peer’s transport stack, not that application code has validated, processed, or permanently stored the message.
An ACK does not mean "saved to disk."
It only means the bytes reached the other machine's network stack. The app could still crash before it finishes processing or writing them.
For durability, the application still needs its own save step, like a database commit that flushes to disk. TCP gives delivery across the network, not permanent storage.
When a packet goes missing
tries to fill the gaps so the final stream still arrives complete and in order:
1. Wait, then resend
If no reply arrives in time, TCP sends the packet again. Each wait gets longer so a busy network is not flooded.
2. Resend sooner
If the receiver keeps saying "I am still waiting for the same piece," TCP assumes that piece is lost and resends quickly.
3. Resend only what is missing
The receiver can say exactly which pieces arrived, so TCP only replaces the gaps.
TCP vs UDP in plain words
Think of two ways to send news across town. is careful and checks that every piece arrived in order. is quick and light: it sends each piece and moves on, even if a few never arrive.
TCP = tracked delivery
You send something important and wait for confirmation. If a piece is missing, it is sent again. Slower, but you can trust the final result.
UDP = send and keep going
You send updates quickly without waiting for receipts. A missing update is okay if the next one is more useful anyway, like the newest game position or voice sample.
| Feature | TCP | UDP |
|---|---|---|
| Setup | Says hello first | Just sends |
| Reliability | Delivers in order, fills gaps | Best effort; gaps may remain |
| Extra overhead | Larger headers, more bookkeeping | Very small headers |
| Sharing the network | Slows down when the path is busy | No built-in slowdown |
| One lost packet | Can pause the whole stream | Other packets keep moving |
| Who fixes loss? | TCP itself | Your app, or nobody |
| In the browser | Easy (HTTP, WebSocket) | Only through WebRTC or HTTP/3 |
| Simple picture | Tracked delivery | Send and keep going |
| Common uses | Web, email, files, databases, SSH | Games, calls, DNS, live video, QUIC |
When UDP is the better story
is useful when waiting for a missing packet would hurt more than skipping it. There is no long hello, and the protocol itself does not promise delivery. Your app decides what to do if something never arrives.
What apps usually do with gaps
Games
Positions arrive many times per second. An old missed update is useless. The next packet already has the current place.
Voice and video calls
A tiny glitch is often better than a long freeze while the network resends old audio. often uses UDP here.
A lookup is often one small question and one small answer. If nothing comes back, just ask again.
A live game example
You are watching a live match and one tiny video piece is lost.
Careful thinking
Stop and wait for the missing piece. The stream freezes, and by the time it arrives the moment may already be over.
Live thinking
Skip the tiny glitch and keep playing. You stay with the live moment instead of waiting for yesterday's frame.
Browsers do not expose raw UDP
Regular JavaScript cannot open a raw socket. That is mostly a safety choice. Video calls still use UDP under the hood through , and uses UDP inside the browser engine. For most web apps, you still work with -based or unless you use those special paths.
A simple way to choose
Prefer when…
- Every byte matters (files, payments, databases)
- Order matters (chat, logs)
- You want easy browser support
- You do not want to invent reliability yourself
Prefer when…
- Old data is worse than missing data (game positions)
- Freshness matters more than perfection (calls)
- The message fits in one small packet ()
- You control both ends and can build your own rules ()
How to choose UDP (and when to mix)
Choose UDP when late data is worse than missing data. Even then, browsers and mixed systems often still use TCP for setup, auth, and control.
UDP-friendly jobs
- Calls, live video, and interactive games
- Telemetry where the next sample replaces the last
- Tiny one-packet questions like classic DNS
- Custom reliability stacks such as QUIC when you control both ends
Caveats and mixed designs
- Browser JavaScript cannot open raw UDP; use WebRTC or HTTP/3
- Common pattern: TCP/HTTP for signaling and auth, UDP/WebRTC for media
- Use a reliable application protocol for state-changing APIs; HTTPS over HTTP/3 is reliable too.
- A custom UDP protocol also needs congestion control, pacing, and limits on retransmission.
How HTTP got faster: 1.1 → 2 → 3
The meaning of stayed familiar: methods, paths, headers, status codes. What changed is how those requests share a connection and how quickly can start, especially on busy pages and mobile networks.
- Can reuse one connection for many requests
- Responses on one connection still wait in order
- Browsers often open several connections to work around that
- Many requests share one connection at the same time
- Headers shrink after the first time they appear
- One lost TCP packet can still pause everything on that connection
- Runs on over instead of TCP
- Repeat visits can start sending useful data sooner
- One lost packet hurts one stream, not the whole page load
- Can keep going when a phone switches from Wi‑Fi to cellular
HTTP/2: many requests, one conversation
breaks traffic into small frames so several requests can share one connection. A slow response no longer has to block every other response on that same pipe.
Before:
Browsers often open several TCP connections. On each one, responses still wait in line. If the first response is slow, the others behind it wait too.
After:
Many requests share one connection. Pieces of different responses can arrive interleaved, so one slow file does not freeze the whole page load as easily.
Server push
After you ask for a page, the server may send CSS or JS it knows you will need next. Helpful in theory; in practice, caching makes this less common than multiplexing itself.
Smaller headers
The first time a long header appears, it is remembered. Later requests can send a short reference instead of repeating cookies and user-agent strings every time.
HTTP/3 and QUIC: fewer freezes on bad networks
QUIC runs over UDP but provides its own reliable streams, encryption, loss recovery, and congestion control. Consequently, HTTP/3 is suitable for reliable API traffic; “uses UDP” does not mean “loses application requests without recovery.” Stream independence prevents missing bytes in one stream from blocking delivery of unrelated streams, although all streams still share connection-level resources and congestion conditions.
still feels like to your app, but it rides on over . That matters most when the network is lossy or a phone switches networks mid-session.
Why people like QUIC
- Repeat visits can start useful data sooner
- A lost packet hurts one stream, not every download on the connection
- A phone can keep the conversation alive when its changes
- Encryption is built into the transport, not bolted on afterward
Starting sooner on a return visit
Older + path
Say hello, prove identity, then finally send the request. Several can pass first.
on a repeat visit
If the client already knows the server, useful data can ride in the first packet.
Where QUIC fits in the story
QUIC provides reliable streams, congestion control, and encryption over UDP. HTTP/3 uses these streams to carry HTTP requests and responses. The useful distinction is between losing data within one stream and making unrelated streams wait for that same loss.
What it is
Reliable, shared, encrypted streams over UDP. HTTP/3 is normal HTTP meaning riding on QUIC instead of TCP.
Why it helps
Faster return visits, better behavior when a phone changes networks, and less freezing across unrelated downloads.
What not to do
Do not redesign everything around QUIC. Turn it on at the edge when useful, and keep most API design on plain HTTP semantics.
TLS 1.3: the lock starts sooner
is how the client and server agree on secret keys and prove the server is real. Newer TLS spends fewer on that hello, so encrypted data can begin sooner. That is why feels snappier with TLS 1.3.
TLS 1.2
More back-and-forth before the channel is ready. Encryption starts later.
Client says hello
Server answers with certificate and key material
Client finishes key setup
Server confirms
Then encryption is ready
TLS 1.3
Key ideas travel earlier, so one round trip is often enough for a fresh connection.
Client says hello and shares key material
Server answers with key material, certificate, and finish
Client confirms
Encryption is already underway
What to remember
- Fresh connections usually need fewer waits than TLS 1.2
- Return visits can resume even faster
- Old weak algorithms were removed
- More of the handshake itself is protected
DNS: turning a name into an address
The client usually asks a recursive resolver, which answers from cache or queries the DNS hierarchy until it reaches an authoritative server for the name. A hostname can map to several addresses and those answers can change. The TTL tells caches how long an answer can be reused; it does not force an already-open TCP connection to reconnect. During a migration, account for cached answers and existing connections separately.
When you type a site name, your device asks for the matching . It usually checks nearby caches first, then asks farther helpers until an authoritative answer arrives.
| Record | What it maps | Why it matters |
|---|---|---|
| A | name → IPv4 | Most common web lookup |
| AAAA | name → IPv6 | Newer address family |
| CNAME | alias → real name | Often used with CDNs |
| SRV | service → host + port | Finding a service, not just a site |
Rough latency numbers that keep you honest
These are ballpark times, not exact lab measurements. Use them to ask: is this delay from memory, disk, the same region, or another continent?
| Operation | Latency | Notes |
|---|---|---|
| L1 cache reference | 0.5 ns | |
| L2 cache reference | 7 ns | 14x L1 |
| Main memory reference | 100 ns | 200x L1 |
| SSD random read | 16 μs | 150x memory |
| HDD random read | 2 ms | 20,000x memory |
| Same-datacenter round trip | 0.5 ms | |
| Redis/Memcached GET | 0.1-0.5 ms | network + lookup |
| Read 1 MB from SSD | 1 ms | |
| Cross-region round trip (US-EU) | 70-150 ms | |
| TCP handshake | 1.5 RTT | ~1-225ms |
| TLS 1.3 handshake | 1 RTT | ~1-150ms |
| QUIC 0-RTT (repeat) | 0 RTT | instant! |
| DNS lookup (uncached) | 20-120 ms |
UDP in the real world
The pattern is the same in different products: if waiting for a missing packet ruins the experience, send quickly and let the app decide what to do with gaps.
Video
Many on-demand streams still use with adaptive quality. Live calls and some live streams prefer because a tiny glitch is better than a long freeze.
Games
Position updates arrive many times per second. An old missed update is less useful than the newest one that just arrived.
and
DNS often fits in one small question and answer, so UDP is a natural fit. QUIC then builds careful streams on top of UDP for .
Which protocol fits which job?
Start from the job, not from the newest acronym. Ask whether you need perfect delivery, low delay, browser support, or control of both ends.
| Use Case | Protocol | Why |
|---|---|---|
| Public REST API | HTTP/2 + TLS 1.3 | Works almost everywhere; easy to cache |
| Internal services | gRPC (HTTP/2) | Typed, compact, good for streaming |
| Realtime chat | WebSockets | Both sides can talk anytime |
| Live notifications | SSE over HTTP | Server pushes updates; simple reconnect |
| Video | HLS/DASH or UDP/WebRTC | On-demand vs live call needs differ |
| Online games | Custom UDP | Newest update matters more than old ones |
| Mobile-heavy API | HTTP/3 (QUIC) | Handles network switches and loss better |
| IoT telemetry | Lightweight messaging over TCP | Small messages, publish/subscribe style |
How to debug network problems calmly
Measure a timeline before changing protocols: DNS lookup, connection establishment, TLS negotiation, request upload, time to first response byte, and response download. A slow first byte with fast setup may indicate application queuing or database work; a slow large download may indicate bandwidth or loss. Compare cold and reused connections, and check whether a proxy introduces its own timeout. This separates a network symptom from a server bottleneck.
A vague "it is slow" becomes clearer when you split the path into names, connection setup, encryption, transport health, and the app itself.
Ask in order
- Did point to the place you expected?
- Did or and finish cleanly?
- Are packets being lost or resent?
- Is a proxy buffering, rewriting, or timing out?
- Is the app failing fast, or waiting forever upstream?
Measure the pieces
- DNS time, connect time, TLS time, time to first byte, download time
- Which version clients actually use
- Retries, resets, timeouts, and packet loss
- Cache hits, response size, and connection reuse
- Client world: browser, mobile network, corporate proxy
Where time goes in one request
A user action is a chain of waits: find the name, open a connection, encrypt, send the request, do server work, download the response, then render.
Read the diagram definition
sequenceDiagram
autonumber
participant Client
participant DNS
participant Edge as Edge or proxy
participant App as Application tier
participant Data as Cache or database
Client->>DNS: Resolve host, often cached
DNS-->>Client: Address from DNS records or traffic policy
Client->>Edge: TCP 3-way handshake or QUIC setup
Client->>Edge: TLS handshake and protocol negotiation
Client->>Edge: Send headers and optional body
Edge->>App: Reuse pooled upstream connection
App->>Data: Read, write, or cache lookup
Data-->>App: Result
App-->>Edge: Status, headers, body
Edge-->>Client: Compressed response bytes
Client->>Client: Parse, execute, render, cacheSetup
A cold DNS lookup, TCP hello, and TLS check can burn one or more round trips before your app code even runs.
Bytes
Big cookies, fat headers, and large JSON bodies make upload and download slower. Compression and smaller payloads help.
Client world
Browsers add rules and limits. Phones add radio wake-up, loss, and network switches.
Cold start
DNS + TCP + TLS can easily cost a few hundred milliseconds on a 100ms path before useful request bytes finish setup.
Warm connection
A reused HTTPS connection can send immediately and skip most of that setup tax.
Header bloat
Large cookies and auth headers add cost on every request, even before the body starts.
Smaller bodies
If a 50 KB JSON response compresses to 10 KB, transfer size falls by 40 KB. The client still decompresses and parses the original JSON structure, so compression alone does not reduce JSON parsing work. Removing unneeded fields can reduce both transferred data and parsing effort.
Why reusing a connection feels so much faster
Saying hello once and keeping the pipe warm beats paying the hello tax on every request, especially when latency is high or you make many calls.
Without reuse
Twenty separate cold calls can burn seconds just on setup if they cannot overlap well.
With keep-alive
The first call pays setup. The next ones mostly pay for server work and moving the payload.
With multiplexing
Many requests can share one encrypted connection at once, which is how modern pages stay efficient.
Your app vs the plumbing underneath
Your code talks in HTTP or gRPC meaning. Underneath, sockets, packets, and congestion control move the bytes. Keep those two stories separate and systems get easier to reason about.
Your app
- Methods, paths, bodies, status codes, auth
- Retries, timeouts, and business rules
- Choosing HTTP, WebSockets, gRPC, or custom framing
The transport
- IP routing, TCP or UDP behavior, congestion windows
- Buffers, resends, and whether loss pauses one stream or everything
- QUIC may live in userspace, but the idea is the same: meaning vs packet plumbing
Try it: watch one request in packets
A packet capture turns the story into evidence. You can see where time went: name lookup, hello, encryption, first response, or lost packets.
- Run
curl -v https://example.com/api/healthonce cold, then again within a minute while the connection is still warm. - Capture traffic with Wireshark or tcpdump, filtered to your host on
tcp port 443. - Mark , the hello, the hello, and the first request and response.
- Compare cold vs warm: how many waits disappear when the connection is reused?
- Look for retransmits. Loss often shows up in the capture before your app logs a timeout.
Correctness invariant
What must never become false
Once you pick a transport for a message class, its delivery contract stays fixed for that class: reliability (retransmit transport data, while application outcomes may remain uncertain after a timeout), order (byte-stream vs datagram), and latency budget (wait-and-retransmit vs drop-and-continue). Do not silently switch a payment or login path to best-effort , or a live frame path to "must wait for every lost packet" , without changing the product promise users see.
Quantitative example: handshake tax on a 100 ms path
Suppose client ↔ edge is 100 ms. In a simplified loss-free model, a cold connection costs about 1 RTT before the client can send its TLS handshake, then 1.3 costs about 1 more RTT before ordinary application data: roughly 200 ms of setup. The request and first response byte add about another RTT, giving roughly 300 ms before server processing and DNS. Twenty sequential cold calls repeat that setup cost; parallel calls overlap it, so their wall times must not simply be added. Keep-alive / multiplexing pays that tax once; 0-RTT on a resumed path can reduce setup waiting only for operations permitted by the application’s replay policy. Early data can be replayed and may be rejected by the server. By contrast, a live game tick over may accept a 1–2% packet loss rather than adding one extra RTT of retransmit delay that makes the update stale.
Failure timeline: loss, HOL blocking, then timeout
T+0 Client sends HTTP/2 stream A (CSS) and stream B (API JSON) on one TCP T+20ms One TCP segment carrying stream-A bytes is lost on the path T+40ms Stream B's packets arrive at the kernel, but TCP holds them (HOL) T+120ms Illustrative loss-detection point; TCP retransmits the missing segment T+140ms Stream B reaches its application deadline while bytes are still blocked T+160ms Missing bytes arrive; transport delivery resumes after B has timed out Outcome One lost packet delayed an unrelated request; user sees timeout, not "CSS slow"
That is TCP head-of-line blocking under multiplexing. / keeps per-stream loss from freezing sibling streams, but loss still costs retransmit delay on the affected stream.
Try it: TCP recovery versus UDP exposure to loss
Adjust loss, pick TCP or UDP, and send bursts. TCP pays extra round trips to repair the stream; UDP leaves gaps for your application to detect.
No packets yet. Send a burst to populate the timeline.
- Delivered
- 0
- UDP drops
- 0
- TCP retransmits
- 0
- Total events logged
- 0
TCP retransmits until each segment is acknowledged or the connection gives up. UDP exposes loss to the application immediately.
Exercises
1. Choose the transport contract
You ship a payment confirm API and a 30 fps spectator video feed. For each, state reliability, order, and max acceptable extra delay on 2% loss. Which stack (TCP+TLS+HTTP/2, QUIC/HTTP/3, custom UDP) fits, and what must never become false if you get it wrong?
2. Cold-start budget math
RTT = 80 ms. Estimate time-to-first-byte for: cold TCP+TLS 1.3; warm keep-alive; QUIC 0-RTT resume. Your SLO is TTFB p95 < 200 ms. Which setups pass, and how many parallel cold connections break the budget?
3. Timeout vs retransmit
Client timeout is 100 ms; path RTT is 60 ms; one segment is lost. Will the app timeout before TCP's first retransmit lands? What do you change first: timeout, connection reuse, or protocol (HTTP/2 → HTTP/3)?
Primary references
Protocol primary sources, not generic interview books.
What to take with you
Start with and for most products. Reuse connections so you are not paying the hello tax again and again. Use when many requests share one path, and when mobile loss or network switches matter. Remember that is often the first steering point, and that one saved compounds across a huge audience.
Practice and further reading
Use these exercises to connect the lesson to a design decision. State your assumptions, trace what happens to one request, and explain the rule that must remain true even during a failure. That rule is the design's correctness invariant.
Focus for this lesson: Choose transport and application protocols from delivery, ordering, congestion, latency, middlebox, security, and evolution requirements.
Explain the decision
When is UDP preferable even though it does not guarantee delivery?
Read the reasoning
When the application can tolerate or repair loss and values message boundaries or avoiding head-of-line blocking, as in realtime media or custom transports such as QUIC.
Apply it to a production scenario
Users report good server latency but slow page loads only on lossy mobile networks. What protocol path do you inspect?
Read one approach
Compare DNS, TCP/TLS setup, retransmission, HTTP/2 connection-level loss effects, QUIC recovery, MTU, and radio handover behavior.
Work through the numbers
Estimate cold HTTPS setup on a 90 ms RTT path using DNS, TCP, and TLS 1.3 before the request.
Read the worked calculation
A simplified serial budget is roughly 3 RTT = 270 ms before server work; resumption, cached DNS, and QUIC can change the count.
Reason through a failure
What must a protocol migration preserve?
Read the recovery reasoning
Authentication, ordering assumptions, retry semantics, observability, and fallback behavior across old clients and intermediaries.
Sources and further study
Continue with TCP Congestion Control Mechanisms.