Most candidates can draw boxes and arrows, but freeze when an interviewer asks “what actually happens on that arrow?” Networking is the layer underneath every design, and a crisp mental model of it separates a senior answer from a junior one. You don’t need to recite RFCs — you need to reason about round trips, connection reuse, and which protocol fits which traffic shape.
What happens when a client makes a request
Before a single byte of your API response comes back, a lot has already happened:
- DNS resolution — the client turns
api.example.cominto an IP address. This can be one or more round trips, but results are cached aggressively (by the OS, the browser, and recursive resolvers), so it’s usually near-free after the first lookup. - TCP handshake — a three-way handshake (
SYN,SYN-ACK,ACK) establishes the connection. That’s one round trip before any data flows. - TLS handshake — for HTTPS, the client and server negotiate keys. A full handshake is one to two round trips; session resumption and TLS 1.3 0-RTT cut repeat connections to almost nothing.
- HTTP request/response — finally, the actual request goes out and the response comes back.
Why round trips dominate latency
The single most useful number here: one round trip across a continent is roughly 40–80 ms, and across the globe it can exceed 200 ms. Bandwidth has grown enormously, but the speed of light has not. So the latency of a request is dominated by how many round trips it takes, not how many bytes you send.
Cold connection (no reuse):
DNS (cached ~0) + TCP (1 RTT) + TLS (1 RTT) + request (1 RTT) ≈ 3 RTTs
Warm connection (keep-alive):
request (1 RTT) ← the handshakes are already paid forThis is why connection reuse matters so much. HTTP keep-alive, connection pools, and persistent connections amortize the handshake cost across many requests. When you say “we’ll keep a connection pool to the database and reuse TLS sessions,” you’re showing you understand where the time goes.
The HTTP versions
| Version | Transport | Key property | Weakness |
|---|---|---|---|
| HTTP/1.1 | TCP | One in-flight request per connection | Head-of-line blocking; browsers open ~6 connections per host |
| HTTP/2 | TCP | Multiplexed streams over one connection; header compression | TCP-level head-of-line blocking (one lost packet stalls all streams) |
| HTTP/3 | QUIC (UDP) | Independent streams, built-in TLS, faster handshake | Newer; some networks throttle UDP |
HTTP/1.1 sends one request at a time per connection. If a response is slow, everything behind it waits — head-of-line blocking. Browsers work around this by opening multiple parallel connections.
HTTP/2 multiplexes many logical streams over a single TCP connection and compresses headers, which is a big win for pages with many small assets. But because it rides on TCP, a single lost packet stalls all streams until it’s retransmitted.
HTTP/3 moves to QUIC, a protocol built on UDP that handles streams independently, so one lost packet only stalls its own stream. It also folds the TLS handshake into the connection setup, reducing round trips. For a latency-sensitive, global service, HTTP/3 is increasingly the default at the edge.
Pushing data to the client
Plain request/response is pull-based: the client asks, the server answers. Many systems need the server to push updates — a chat message, a live score, a notification. There are four common approaches.
- Short polling — the client re-requests every N seconds. Dead simple, but wasteful and laggy. Fine when “near-real-time” is acceptable and you want minimal moving parts.
- Long polling — the server holds the request open until it has data, then responds; the client immediately re-requests. Near-real-time without new infrastructure, but it ties up a connection per waiting client.
- Server-Sent Events (SSE) — a one-way, server-to-client stream over ordinary HTTP. Great for feeds, notifications, and live dashboards. It auto-reconnects and is simpler than WebSocket, but it only flows one direction.
- WebSocket — a persistent, full-duplex connection after an HTTP upgrade handshake. The right tool for chat, collaborative editing, and multiplayer games, where both sides send frequently. The cost is that it’s stateful — you now have long-lived connections to manage, route, and balance.
Rule of thumb: if the client rarely talks back, use SSE; if both sides are chatty, use WebSocket; if you just need “eventually fresh,” polling is fine.
gRPC for service-to-service calls
Between your own backend services, you usually don’t want REST over JSON. gRPC runs on HTTP/2 and serializes messages with Protocol Buffers (a compact binary format defined by a schema). You get:
- Speed — binary encoding is smaller and faster to parse than JSON.
- Typed contracts — the
.protoschema is the source of truth; clients and servers generate code from it. - Streaming — client-, server-, and bidirectional streaming come built in.
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc StreamUpdates (SubReq) returns (stream UserEvent);
}The trade-off: gRPC is awkward from browsers (it needs a proxy like gRPC-Web) and harder to debug by hand than REST. So the common pattern is REST/GraphQL at the edge for clients, gRPC between internal services.
Load balancing and the edge
Where a request first lands also matters. A quick recap (the Common Components lesson goes deeper):
- L4 load balancers route on IP and port without reading the payload — very fast, protocol-agnostic.
- L7 load balancers understand HTTP and can route by path, header, or cookie, enabling smart routing and TLS termination.
- CDN / edge termination — terminating TLS at an edge PoP close to the user cuts the handshake round trips dramatically, then reuses a warm, long-lived connection back to your origin. This is one of the cheapest latency wins available.
In the interview
When you place a protocol on a diagram, justify it by latency and direction:
- “Clients connect over HTTP/2 so a single connection multiplexes their requests; we terminate TLS at the CDN to save round trips.”
- “The live feed uses SSE — it’s one-way and reconnects for free, so WebSocket would be overkill.”
- “Chat uses WebSocket because both users send constantly, and we route connections to the right server via a connection registry.”
- “Internal calls are gRPC for the typed contract and streaming; the public API stays REST for cacheability and ease of use.”
That reasoning — not reciting that TCP has three handshake steps — is what signals depth.
Key Takeaways
- Latency is round trips, not bytes. One cross-continent RTT is ~40–80 ms; minimise handshakes by reusing connections and resuming TLS.
- Pick the HTTP version for the traffic shape. HTTP/2 multiplexes small assets; HTTP/3 (QUIC) avoids TCP head-of-line blocking for global, latency-sensitive traffic.
- Choose a push mechanism by direction. SSE for one-way server push, WebSocket for full-duplex, polling when near-real-time is enough.
- Use gRPC between services, REST/GraphQL at the edge. Binary + typed + streaming internally; human-friendly and cacheable for clients.
- Terminate TLS at the edge. A CDN PoP close to the user turns three cold round trips into one warm one.
