Core Concepts · Networking

You’re nearly always designing systems of independent devices that talk over a network. The field is vast, but interviews only lean on a handful of layers and protocols. This is that handful — purpose, mechanism, and when to reach for each.

How much to know

Networking runs deeper in infrastructure and distributed-systems interviews. For full-stack and product roles a surface understanding is usually enough — but if your interviewer just came off an on-call rotation wrestling with load balancer or CDN problems, expect probing. Knowing the fundamentals helps you make better decisions even when the fine details aren’t tested.

01Networking 101 & the layered model

At its core, networking is about connecting devices so they can communicate. Networks are built on a layered architecture — the OSI model — which dramatically simplifies life for the application developers sitting on top.

Core idea — layers are abstractions

Each layer lets you reason about communication in terms relevant to your application, ignoring the layer below. Requesting a webpage doesn’t require knowing which voltages represent a 1 or 0 on the wire — you just use the next layer down. It’s like calling open() in your language instead of instructing the disk how to read bytes.

The three layers that matter in interviews

The full stack is fascinating, but three layers come up most. Here’s what each does before we dive in:

L7
Application layerDNS, HTTP, WebSockets, WebRTC — protocols for web-app data, built on TCP (or UDP for WebRTC).
L4
Transport layerTCP, QUIC, UDP — end-to-end services adding reliability, ordering, flow control on top of IP.
L3
Network layerIP — routing and addressing. Breaks data into packets, best-effort delivery to any destination IP.
…
Physical / link layersWires, radios, hardware. Below our concern — the abstraction hides them.
The networking “cake”: application protocols at the top, physical wires at the bottom. Interviews live in L3–L7.
Instructor insight — layers depend on, but are oblivious to, each other

HTTP depends on a TCP connection being established; TCP assumes it can use IP addresses to route packets. Each layer builds on the one below and stays ignorant of its details. That obliviousness is exactly what makes the abstraction useful. (IP dominates outside AI labs; InfiniBand shows up for massive ML training workloads.)

Walkthrough — what happens on a simple web request

Type a URL and several layers spring into action. To fetch a page over HTTP on TCP: first DNS converts a human-readable domain like hellointerview.com into an IP like 32.42.52.62. Then a carefully orchestrated sequence sets up a connection, sends the request, gets a response, and tears the connection down.

1
DNS resolution. Resolve the domain name to an IP address.
2
TCP handshake — three-way: SYN (client requests) → SYN-ACK (server acknowledges) → ACK (client confirms). Only now is the connection established.
3
HTTP request. Client sends an HTTP GET for the page.
4
Server processing. Server retrieves the page and builds a response. This is usually the only latency most SWEs think about and control.
5
HTTP response. Server returns the page content.
6
TCP teardown — four-way: FIN → ACK → FIN → ACK. Each side closes its half of the connection.
One conceptual request/response — but many packets and round trips underneath.

These handshake details rarely feature directly in a system design interview (they were once a popular “what happens when you type a URL and press enter?” question, less so now in Big Tech). But three observations here we’ll build on:

Three things to carry forward
  1. Simplified mental models. The app takes reliability and ordering for granted — TCP delivers data correctly and in order, and tells the app if it can’t. DNS finds the IP; IP + the routing hardware between you, your ISP, and backbone providers gets data there.
  2. Latency hides in the layers. One “request” is really many packets and exchanges, each adding latency you can ignore… until you can’t. The higher up the stack, the more latency and processing. (This matters for load balancing shortly.)
  3. The connection is state. Both client and server must maintain it. Without HTTP keep-alive or HTTP/2 multiplexing, you repeat this setup for every request — significant overhead, and central to systems needing persistent connections.
Layer 3

02Network layer — the IP protocol

The lowest layer we care about is dominated by IP, responsible for routing and addressing. Nodes are usually assigned IPs by a DHCP server when they boot. These addresses are arbitrary — they only mean something because we tell people about them. You can build a private network and assign any IPs you like, but for internet traffic to find your machines you need routable addresses allocated by a RIR.

Definition — public vs private IPs

Public IPs identify devices on the internet. They’re assigned by a central body, and the internet’s routing infrastructure is optimized to know where they live. Private IPs you assign yourself on an internal network — the only requirement is that you remember where they are and your routers know about them.

The key property of public IPs: routing infrastructure knows where they are. Any address starting with 17 (e.g. 17.0.0.0) belongs to Apple — the backbone knows a packet for those addresses goes to Apple’s routers. There’s far more to internet routing, but it won’t matter for our purposes, so we move up the stack.

Instructor insight — where you’ll see each in a design

In the video walkthrough the author frames it operationally: public addresses are for the internet-facing edge — your API Gateway, load balancers, anything the outside world must reach. Private addresses are for everything else — microservices and internal hosts. If you load-balance across IPs, you have to track which host is where and which ones you want to use.

Memorable trap he gives for private ranges (like 192.168.0.1, probably your home router): don’t give your toaster an IP that Google also uses, or your packet meant for Google goes to your toaster. Private ranges exist precisely to eliminate that overlap.

▸Extra context — IPv4 vs IPv6 (from the video)

Not in the written guide, but the walkthrough adds it: there are two address formats. IPv4 addresses are 4 bytes (the familiar dotted notation); IPv6 addresses are 16 bytes, arranged in 2-byte pairs. The main practical difference is that we’ve run out of IPv4 addresses but not IPv6. You’ll typically use IPv4 externally (more compatible) and IPv6 internally (more modern).

Layer 4

03Transport layer — TCP, UDP, QUIC

The transport layer establishes end-to-end communication between applications, giving guarantees instead of a jumbled mess of packets. Three protocols are in wide use: TCP, UDP, and QUIC.

Instructor insight — what transport adds over IP

With IP addresses in hand you can send a block of binary data to a host, but you’re missing two things: context (which application it’s for and from — solved by ports) and ordering / delivery confirmation. IP doesn’t provide these; transport protocols do.

For interviews the real choice is usually TCP vs UDP. QUIC is newer — it aims to deliver TCP-like benefits with modernization and performance gains, and it’s gaining ground, but it isn’t yet ubiquitous. Treat it as “a better version of TCP without the same broad adoption.”

Tip — QUIC / HTTP/3

Performance-oriented interviewers may be impressed if you know modern protocols like QUIC and HTTP/3 (HTTP over QUIC), but most interviewers want your time spent elsewhere in the design. A commenter’s clarification worth remembering: QUIC is built on UDP and is an alternative to TCP — not a “newer TCP.”

UDP — fast but unreliable

UDP is the machine gun of protocols — few features on top of IP, but very fast. “Spray and pray” is the right mental image: connectionless, no delivery guarantee, no ordering, no duplicate protection. If you receive UDP datagrams you can see the source and destination IP + port — the rest is a binary blob.

Key characteristics of UDP
  1. Connectionless — no handshake or setup.
  2. No delivery guarantee — packets may be lost silently.
  3. No ordering — packets may arrive out of order.
  4. Lower latency — less overhead means faster transmission.

No setup sounds great, but no delivery guarantee and no ordering kind of suck — so why use it? UDP is perfect where speed matters more than reliability: live video streaming, online gaming, VoIP, DNS lookups. The client is equipped to handle occasional loss.

Example — VoIP & video conferencing

For VoIP, the client just drops the occasional packet — a small audio hiccup — and the conversation stays intelligible. That’s far preferable to retransmitting lost packets and clogging the network with ACKs. The video adds: if you drop a video frame you don’t ask for it again, you drop it from view (maybe stabilize the audio) and keep going. You might still message the sender to lower the transmission rate — you just don’t care about individual packets.

Watch out — browsers don’t do UDP

Browsers have no widespread UDP support outside WebRTC. If your design could use UDP (e.g. spamming hearts/reactions in Facebook Live Comments), plan for browser users too: app users might get a real-time UDP stream while browser users get a slower, batched HTTP stream spread over time in the UI.

TCP — reliable but with overhead

TCP is the workhorse of the internet: reliable, ordered, error-checked delivery. It sets up a connection via the three-way handshake (seen above) and maintains it through the session. That connection is a stream — a stateful connection between client and server, and the basis for ordering: two messages in the same stream arrive in the same order. TCP makes recipients acknowledge receipt and retransmits until they do.

Instructor insight — how ordering actually works

On connection setup TCP starts a sequence and gives each packet a sequence number. If packets arrive out of order or go missing, both sides can tell: receive 1 and 3 and you can infer 2 is missing and ask the sender to resend it; receive 5 right after 3 and you’ll wait a moment for 4 before handing 5 up to the application.

Key characteristics of TCP
  1. Connection-oriented — a dedicated connection before data transfer.
  2. Reliable delivery — data arrives in order and without errors.
  3. Flow control — prevents overwhelming receivers.
  4. Congestion control — adapts to network congestion to prevent collapse.

TCP is ideal wherever data integrity matters — that is, basically everything UDP is not a good fit for. The reliability comes at a cost in throughput and latency: a lost packet must be retransmitted before things continue, and if the two hosts are far apart that retransmission eats real time.

▸Watch out — “guaranteed delivery” has limits (from the video)

TCP guarantees delivery in the sense that you’ll know whether the other host received a packet. It does not guarantee delivery in an absolute sense — it won’t tell you the data was written to disk. Not relevant to CAP theorem, but practically useful: it tells you what happened on the network, not what the far end did with the data afterward.

When to choose each

Most interviewers assume TCP by default — it often needn’t be stated. That’s also the recommendation. You earn points by making a correct case for UDP without bungling the details, so ask yourself whether UDP genuinely fits.

Choose UDP when…
  • Low latency is critical (real-time apps, gaming).
  • Some data loss is acceptable (media streaming).
  • You’re handling high-volume telemetry/logs where occasional loss is fine.
  • You don’t need browser support (or you have an alternative for that client).

Modern apps often use both: a web-based video-conferencing app might use TCP/HTTP for signaling and auth but UDP/WebRTC for the actual audio/video.

FeatureUDPTCP
ConnectionConnectionlessConnection-oriented
ReliabilityBest-effortGuaranteed
OrderingNo guaranteeMaintains order
Flow controlNoYes
Congestion controlNoYes
Header size8 bytes20–60 bytes
SpeedFasterSlower (overhead)
Use casesStreaming, gaming, VoIPEverything else
Layer 7

04Application layer protocols

The application layer is where most developers spend their time. These protocols define how applications communicate and are built on the transport protocols above.

Definition — user space vs kernel space

The application layer is typically processed in “user space,” while the layers beneath run in the OS kernel (“kernel space”). So the application layer is more flexible and easily modified; the lower layers are hard to change but can be very efficient.

HTTP / HTTPS — the web’s foundation

HTTP is the de-facto standard for web data communication: a request–response protocol where clients send requests and servers respond with data. It’s versatile and battle-tested over decades — even RPC applications often ride on it.

Core idea — HTTP is stateless

Each request is independent; the server keeps no memory of previous requests. This is generally good — in system design you want to minimize the stateful surface area of your system. Most simple HTTP servers can be described as a pure function of the request parameters.

You can actually open a TCP connection and type an HTTP request/response by hand with netcat (nc). Requests are simple text: a method (verb) telling your intent, a path, the HTTP version, and headers. Responses carry the data plus a status code and headers.

Common request methods
  • GET — request data; idempotent, no body.
  • POST — send data to the server.
  • PUT — update (replace) a resource.
  • PATCH — update a resource partially.
  • DELETE — delete data; idempotent.
Common status codes
  • 2xx — 200 OK · 201 Created
  • 3xx — 301/302 Moved (perm/temp)
  • 4xx — 404 Not Found · 401 Unauthorized · 403 Forbidden · 429 Too Many Requests
  • 5xx — 500 Server Error · 502 Bad Gateway

Methods and status codes are standardized (think enums); headers are flexible key/value pairs. Most interviewers won’t drill into this detail unless you’re designing a RESTful API.

Instructor insight — content negotiation is great API design

Headers show how to design an interface that’s flexible to unknown future use cases. With Accept-Encoding, a client signals it can handle gzip or br (brotli); the server replies with Content-Encoding: X, choosing the most efficient encoding that client supports. This gives both backward and forward compatibility — new versions introduce new headers, and clients and servers negotiate what to use. A perfect case study for your own API design.

HTTPS adds a security layer (TLS/SSL) to encrypt communications, protecting against eavesdropping and man-in-the-middle attacks. Building a public website? Use HTTPS, without exception — request and response contents are encrypted and safe in transit.

Watch out — encrypted ≠ trustworthy

HTTPS contents are encrypted, but not guaranteed to be generated by your client. Never trust the request body without validating it. Common mistake: putting the user’s ID in the request body and using it for a DB call — an attacker changes the ID and reads arbitrary user data. You can still include user IDs; you just must validate them server-side and never ask for anything you can’t trust.

REST — simple and flexible

HTTP builds websites, but system designs usually concern service-to-service APIs. The three main paradigms are REST, GraphQL, and gRPC — and REST is the most common.

Definition — REST

Representational State Transfer. Clients perform simple operations against resources (think database tables or files). REST pairs the HTTP verbs with conventions about paths and request bodies, usually using JSON. Two pieces: verbs describe the operation (read/write/update); URLs identify the resource.

If you follow the Delivery Framework, your Core Entities often map directly to your API resources. A simple RESTful API:

Read a resource
GET /users/{id} -> User
Update (replace) a pre-existing resource
PUT /users/{id} -> User
{
  "username": "john.doe",
  "email": "john.doe@example.com"
}
Create — server assigns the ID
POST /users -> User
{
  "username": "stefan.mai",
  "email": "stefan@hellointerview.com"
}
Nest resources to represent relationships
GET /users/{id}/posts -> [Post]
Common mistake — thinking in operations, not resources

Engineers used to function calls reach for updateUser or startGame. Those are operations, not resources, so they aren’t RESTful. Model them as updates to resources instead: updateUser → PUT /users/{id}; startGame → PATCH /games with { "status": "started" } (changing status from pending/stopped to running).

REST is the default we’d suggest for interviews — well understood, widely usable, and a good baseline for scalable systems. It won’t be the most performant option for very high-throughput services, and JSON is a fairly inefficient serialization format, but most applications aren’t bottlenecked by request serialization. Reach for GraphQL, gRPC, SSE, or WebSockets only when you have a specific need REST can’t meet.

GraphQL — flexible data fetching

Open-sourced by Facebook around 2015, GraphQL lets clients request exactly the data they need. The problem it solves: teams split into frontend and backend, and when the frontend needs a new page it must either (a) cobble together many backend calls, (b) build huge aggregation APIs that are hard to maintain, or (c) write brand-new APIs per page. None are great.

Two failure modes GraphQL targets

Under-fetching — a page needs many requests and round trips (e.g. 1 call for a user list, then 10 for their details), adding overhead and latency; the screen only loads once all return. Over-fetching — a “kitchen-sink” endpoint returns far more than needed to guard against future use cases, so responses are slow and bloated.

GraphQL lets the frontend describe the shape of data it needs; the backend figures out where to get it and returns it in that shape — and nothing more.

One query for a page showing users, profiles, and their groups
query GetUsersWithProfilesAndGroups($limit: Int = 10, $offset: Int = 0) {
  users(limit: $limit, offset: $offset) {
    id
    username
    profile { id fullName avatar }
    groups {
      id name description
      category { id name icon }
    }
    status { isActive lastActiveAt }
  }
  _metadata { totalCount hasNextPage }
}
Instructor insight — where it shines, and why interviews rarely need it

GraphQL fits when the frontend iterates fast (experiments, unfixed requirements) or when multiple teams query overlapping data through different backends. But in interviews you’re usually the sole author with fixed requirements, and interviewers want to see how you optimize specific query patterns — where GraphQL is often just in the way. Bring it up when the problem is explicitly about flexibility or deliberately uncertain requirements (Newsfeed-style endpoints are a classic fit). Executing GraphQL can also add latency and complexity on the backend — sometimes the very bespoke code you were trying to avoid.

gRPC — efficient service communication

gRPC is a high-performance RPC framework from Google (the “g”) built on HTTP/2 and Protocol Buffers. Think of Protocol Buffers like JSON but with a rigid schema (it looks like a C/C++ struct) that enables far more efficient serialization.

A Protocol Buffer message
message User {
  string id = 1;
  string name = 2;
}

Instead of a chunky JSON object with embedded schema (≈40 bytes)…

{ "id": "123", "name": "John Doe" }

…you get a binary encoding (≈15 bytes) of the same data — skinny tags and variable-length string encoding. Less space, less CPU to parse:

0A 03 31 32 33 12 08 6A 6F 68 6E 20 64 6F 65
gRPC adds service definitions on top of protobuf
message GetUserRequest { string id = 1; }
message GetUserResponse { User user = 1; }

service UserService {
  rpc GetUser (GetUserRequest) returns (GetUserResponse);
}

These compile into client and server stubs consumable by many languages (Java, C++, Node, Ruby, and more). gRPC includes features for microservices at scale — streaming, deadlines, client-side load balancing, rudimentary auth. The headline: it’s a binary protocol that’s faster and more efficient than JSON over HTTP.

Where to use it — internal services

gRPC shines for internal service-to-service communication, especially when performance is critical or latency is dominated by the network rather than the server’s work — some benchmarks show ~10× throughput. Strong typing catches errors at compile time. The video adds: this is basically how Google builds services internally; the main friction is that external clients and browsers don’t support gRPC natively, and binary-on-the-wire is harder for other teams to debug.

Design rule — REST outside, gRPC inside

Use REST for public-facing APIs and gRPC for internal service-to-service — especially when exchanging binary data or when performance is critical. In many interviews, REST both internally and externally is fine — build from there based on the problem.

Browser /
external client
→REST / HTTP
API server
→gRPC
Internal
service
Hybrid: widely-accepted, debuggable REST at the edge; high-performance gRPC interconnects behind it — best of both worlds.
Watch out — premature optimization

Interviewers want to see how you think through problems and react to constraints — not a hyper-optimized RPC choice. Don’t optimize your protocol before handling the substantial bottlenecks. Premature optimization is the root of all evil.

Server-Sent Events (SSE) — real-time push

So far, request/response. But many apps need to push data to clients as it happens (stock tickers, notifications). You could poll repeatedly, but then data is delayed by your polling frequency and you pay the overhead of repeatedly opening connections.

Core idea — one response, many messages over time

SSE is a spec on top of HTTP that lets a server stream many messages in a single response. It’s “a nice hack on HTTP.” With normal HTTP you wait for the whole response before processing; with SSE the server sends chunks (via chunked-encoding headers), each line a separate message the client processes as it arrives. Still one HTTP response over one TCP connection — but it dribbles in.

Normal HTTP — one blob, processed only when complete
{
  "events": [
    { "id": 1, "description": "Event 1" },
    { "id": 2, "description": "Event 2" },
    ...
    { "id": 100, "description": "Event 100" }
  ]
}
SSE — each line arrives and is processed as it comes
data: {"id": 1, "description": "Event 1"}
data: {"id": 2, "description": "Event 2"}
...
data: {"id": 100, "description": "Event 100"}
Watch out — connections get severed

You can’t keep an SSE connection open forever — the server, a load balancer, or a middle-box proxy will close it (HTTP requests are expected to return in ~30s–1min). So the standard defines an EventSource object that auto-reconnects, passing the ID of the last message received; servers are expected to track prior messages and resend anything missed during the gap. There are also misbehaving networks that batch all SSE responses into one — the very thing you were avoiding. Most interviewers don’t know these limits and will let you assume they don’t exist, but anyone who’s implemented SSE will probe for real experience.

Where to use it: when clients should get notifications/events as soon as they happen — keeping bidders updated on an auction price, order status over ~15 seconds, or (per the video) streaming AI tokens/responses back to the user as they’re generated, since a full response can take 30 seconds to build.

WebSockets — real-time bidirectional

SSE pushes server→client. When you need real-time bidirectional communication — clients pushing to the server as much as the reverse — you reach for WebSockets: a persistent, TCP-style connection with broad support (including browsers). Unlike request/response, the server can push without being prompted, and clients can too.

How it works
  1. Client initiates a WebSocket handshake over HTTP (backed by a TCP connection).
  2. The connection upgrades to the WebSocket protocol, which takes over that TCP connection.
  3. Both sides can send binary messages to each other.
  4. The connection stays open until explicitly closed.

Upgrading from HTTP is convenient — you can reuse existing HTTP session info (cookies, headers). WebSockets don’t dictate an application protocol: you get a channel for binary packets and define what’s exchanged (serialized JSON messages are a great option, and let you define your service’s API).

Instructor insight — design them as messages, and isolate the state

Design a WebSocket API in terms of messages (e.g. client sends subscribe/unsubscribe, server sends ticker update), not request/response — that’s not how they’re built (use HTTP if you want request/response). And they’re inherently stateful: a connection alive for an hour needs its server alive that whole time, which wreaks havoc on deployments and failures. The interview pattern: put a message broker / notification service at the edge that terminates all the WebSocket connections and exposes methods internal services can call; internal services push messages back out through it. (More in the Realtime Updates guide.)

Watch out — don’t reach for them unprompted

Use WebSockets for high-frequency, persistent, bidirectional communication (real-time apps, games). If you only need request/response, or SSE-style push suffices, they’re overkill. Launching into a WebSocket design without justifying it is a fast “thumbs down” — the infra is expensive and stateful connections at scale force significant accommodations. Also, every piece of infra between client and server (firewalls, proxies, load balancers) must support WebSocket connections; not all do.

WebRTC — peer-to-peer

The most unique protocol here: WebRTC enables direct peer-to-peer communication between browsers with no intermediary server for the data exchange — great for collaborative editors and especially audio/video calling. It’s also the only application-level protocol here that runs over UDP.

Peer-to-peer is trickier than client-server because most clients don’t accept inbound connections (a security measure) and most users sit behind a NAT device. Clients talk to a central signaling server that tracks who’s available and their connection info; once a client has a peer’s info, it tries to connect directly. To get through NAT, WebRTC defines two mechanisms:

STUN & TURN

STUN (“Session Traversal Utilities for NAT”) — techniques like hole punching that let peers discover publicly routable addresses/ports and connect directly. TURN (“Traversal Using Relays around NAT”) — a relay service that bounces traffic through a central server when a direct connection can’t be established (the least efficient fallback).

1
Clients connect to a central signaling server to learn about their peers.
2
Each client reaches a STUN server to get its public IP and port (and do hole punching).
3
Clients share that info with each other via the signaling server.
4
Clients establish a direct peer-to-peer connection and send data (e.g. video) over UDP.
The happy path. If a direct connection fails, fall back to a TURN relay. The signaling server handles many clients cheaply since it never carries the video itself.
Watch out — a niche solution, easy to over-apply

WebRTC sounds seductive, but it’s an absolute pain to get right — even the best implementations still drop connections. In interviews, more candidates go wildly off-trail trying to build peer-to-peer systems than succeed at them. Most problems don’t need peer-to-peer, and you often still need a central server to store state and coordinate anyway (that’s why the Google Docs breakdown uses WebSockets). Stick to WebRTC for audio/video calling and conferencing and you’ll be in good shape.

▸Extra context — WebRTC for collaborative editors & CRDTs

It can occasionally fit collaborative editors that scale to many clients, using CRDTs (Conflict-free Replicated Data Types) to share document state over a peer-to-peer path. In practice most collaborative editors don’t need to scale to thousands of clients, and CRDTs are “an awesome design you may read up on… also probably not necessary for 95%+ of interviews.”

Picking an application protocol

ProtocolShapeReach for it when…
RESTRequest / responseDefault. General-purpose APIs, well understood, good enough for most.
GraphQLRequest / response, client-shapedFlexible/changing frontends, many teams, arbitrary query patterns.
gRPCRequest / response + streamingInternal service-to-service; performance-critical, network-bound.
SSEServer → client streamPush updates for a short window; AI token streaming.
WebSocketsBidirectional streamHigh-frequency, persistent, two-way (games, live apps).
WebRTCPeer-to-peer (UDP)Audio/video calling & conferencing (occasionally collab editors).
Scaling

05Load balancing

We’ve covered the protocols. But how do we scale? Two options: bigger servers (vertical scaling) or more servers (horizontal scaling).

Instructor insight — don’t underrate vertical scaling

The author’s preference is vertical scaling wherever possible — modern hardware is incredibly powerful (servers with terabytes of memory), and many people are “stuck in the early-2010s world” where Google needed commodity hardware. That said, the reality for interviews is that the expected pattern is horizontal scaling: add more servers. But adding boxes to a whiteboard doesn’t help unless you tell clients which server to talk to.

Client
→
Load
balancer
⇉
Server 1
Server 2
Server 3
Load balancing serves two purposes: spread load across servers and provide high availability — if one server dies, clients reach the others.

Two ways: client-side vs a dedicated appliance

Client-side load balancing

The client itself decides which server to talk to. It queries a service registry/directory listing available servers (or asks the servers themselves), then connects directly, periodically syncing that list. This is very fast and efficient: since the client decides, it skips the extra network hop of routing through a balancer on every request — no additional latency in the middle.

Example — Redis Cluster & DNS

Redis Cluster: nodes run a gossip protocol so every node knows every other node. A client asks any node about the cluster and its shards, then hashes the key to pick a shard and uses local node info to reach the right node. Hit the wrong node and Redis returns a helpful MOVED response.

DNS: resolving example.com returns a rotated list of IPs — each client gets a different ordering, so they hit different servers. The resolver is doing client-side load balancing for you. This is also how you avoid a single point of failure at the balancer: run two load balancers (different data centers/regions) and rotate between them via DNS; if one dies, clients try the other.

When client-side works well

Either (1) few clients you control (Redis Cluster client, gRPC’s built-in client-side balancing for internal services) — easy to push updates — or (2) many clients that tolerate slow updates (DNS). For DNS, entries have a TTL: far-flung resolvers cache entries for their own clients, so your updates can’t propagate faster than the TTL (the video pegs this at ~5 minutes to a day) — no good if you must react rapidly to scaling events.

In interviews, client-side balancing works remarkably well for internal microservices (built into gRPC). Many interviewers don’t probe the lines between services, but mention it if asked. For everything else, use a dedicated load balancer.

Dedicated load balancers

Sometimes you don’t want clients refreshing server lists or even knowing multiple servers exist — or you have many uncontrolled clients needing fast updates. A dedicated load balancer is a server or hardware device between clients and backends, deciding where each request goes. It adds a hop per request, but in exchange you get fast server-list updates and fine-grained routing control. Which one you pick depends on the layer it operates at.

Layer 4 load balancers

Operate at the transport layer (TCP/UDP), routing on IPs and ports without inspecting packet contents. The effect is as if you randomly picked a backend and the client had a direct TCP connection to it — the balancer opens a parallel TCP connection to the server and just shuffles packets between the two.

Because a client’s TCP connection through an L4 balancer sticks to the same server for the whole session, L4 is well-suited to protocols needing persistent connections, like WebSockets.

Layer 7 load balancers

Operate at the application layer, understanding protocols like HTTP. They examine request content (URL, headers, cookies) and make smarter routing decisions.

An L7 balancer could send API requests to one server pool and web-page requests to another (like an API Gateway), or pin all of a user’s requests to one server via a cookie. Because it works at the request level, a single client TCP connection carrying multiple HTTP requests can be fanned out across many backends — the underlying TCP connection to your server isn’t really relevant. But you can’t ignore the connection-level reality if you need persistent connections to consistent servers.

L4 — one connection through Client TCP ⟶ balancer opens a parallel TCP ⟶ server. Same server for the whole session. High performance, no inspection.
L7 — request by request Balancer accepts full HTTP requests and can fan each out to any backend. Few server connections, many client connections. Flexible, can terminate HTTPS.
L4 preserves the connection; L7 understands the request. That difference decides which fits.
Decision rule

L7 is the default for HTTP-based traffic — covering everything discussed except WebSockets — thanks to routing options and the ability to terminate HTTPS. L4 is the pick for WebSockets and other persistent/stateful connections, and for high-performance cases needing little application-level processing. Some L7 balancers do support WebSockets, but generally L4 is better for them; L7 offers more flexibility for HTTP solutions like long polling.

Q&AWhy is L4 usually preferred for WebSockets, even though L7 can inspect the HTTP upgrade? (a recurring point of confusion in the source’s comments)+

Balancing a WebSocket can only happen once — during the HTTP upgrade request. After that it’s effectively a persistent, stateful TCP connection with TCP-like frame ordering. An L7 balancer can’t meaningfully rebalance messages midstream: doing so would mean decoding fragmented WS frames from an arbitrary application protocol and opening a WS connection to each backend, breaking ordering guarantees and multiplying connections. So once established, the connection can be inspected but not re-balanced — the only way to rebalance is to close it and force the client to reconnect (a new upgrade request).

Practitioners note both sides: L7 (Envoy, AWS ALB) can handle WebSockets and adds routing on path/host/cookies, but L4 connections can live longer and allow more concurrent WS connections. If you need to read the upgrade request to land the connection on the right server, you need L7 for that step. (Synthesized from the guide’s comment discussion — a distinction the article itself states only implicitly.)

Health checks & fault tolerance

Load balancers also monitor backend health — when a server crashes or loses power, the balancer stops routing to it until it recovers. This automatic failover is what makes them essential for high availability. When a server spins up it announces itself; the balancer runs health checks at configurable intervals/protocols and only routes traffic once the server has returned healthy enough times (and stops when it goes unhealthy).

Instructor insight — shallow vs deep checks

Health checks range from shallow (a simple TCP check — can the server accept a connection?) to deep (an L7 HTTP request inspecting the status code — 200 vs a 500 or no response). Deeper checks catch more failure modes but cost more.

Load balancing algorithms

Round robin or random is usually fine for stateless apps where no server is more popular than another — and new servers naturally start receiving traffic with no special config. For persistent connections (SSE, WebSockets), use Least Connections to avoid one server gradually accumulating all the long-lived connections (some last minutes, some hours).

Real-world implementations
  • Hardware: F5 Networks BIG-IP — can scale to hundreds of millions of requests/sec.
  • Software: HAProxy, NGINX, Envoy — more limited (≈1M transactions/sec).
  • Cloud: AWS ELB/ALB/NLB, Google Cloud Load Balancing, Azure Load Balancer.

Scaling the load balancer itself is almost never part of a SWE interview — but if throughput is huge, mentioning hardware load balancers is a good way out.

Deep dives

06Common deep dives & failure modes

We have protocols, load balancing, persistent connections, and high availability. Beyond those, a few practical considerations are ripe for deep-dive probing — and can make or break a design.

Regionalization & latency

Global services distribute servers around the world. A common pattern: multiple data centers in one region (Amazon calls these availability zones) so a pipe breakage in one building doesn’t take down the service, then replicate that across cities worldwide. Great for humanity — but it introduces networking challenges.

The physics you can’t beat

Physical distance drives latency. Light in fiber travels at ≈2/3 of light in vacuum, ≈200,000 km/s. A New York↔London round trip (≈5,600 km) has a theoretical minimum of ≈56 ms just from signal propagation, before any processing (nearby servers are <1 ms). The video rounds this to “about 80 ms no matter what” — a problem if you make many back-and-forth requests across the Atlantic.

Core idea — data locality

Highest performance comes when data is as close as possible to the computation that needs it. For a regional app, keep all the data needed to satisfy a query (a) close together and (b) close to the user. If user data is in LA but web servers are in New York, every DB query eats tens of milliseconds of network latency — before processing. Some latency is unavoidable (users are simply far apart), but two strategies help within the constraints of physics.

Instructor insight — collocate before you relocate

One user request from London to New York triggers many web-server↔database round trips before the response goes back. It would be silly to move the web server to London (short hop to user) but leave a long hop back and forth to the database. Keep processing and data in approximately the same place first; then get that whole unit close to users. For data that must be everywhere (Reddit posts read across time zones), your options are partition globally (keep data where it’s most used) or replicate (write locally, replicate to other regions for fast reads) — replication inherently adds lag between a write in the US and its availability in Europe, which may be acceptable.

Content Delivery Networks (CDNs)

The most common latency-reduction strategy. CDNs are networks of servers strategically placed around the world — often hundreds or thousands of cities. These edge locations act like gateways: you connect to the nearest one. If that edge server can answer your request, you get lightning-fast responses — the data is just up the road.

User
→
Edge node
(cache, nearby)
→cache miss
Origin server
(far away)
A CDN is a cache. Cache hit → served immediately from the edge. Cache miss → the edge acts as a proxy to the origin. Either way it also reduces backend load.

This works because of caching: data that doesn’t change often can be cached at the edge and returned from there — especially effective for static content like images and videos. In interviews you’ll see CDNs when data is very cacheable and queried globally (e.g. caching Facebook search results) — minimizing latency and reducing backend load. When data can’t be cached, the edge node forwards to the origin server, acting as a proxy.

Regional partitioning

When you have many users in one region, partition data by region so each region only holds data relevant to it.

Example — Uber

You order rides from drivers in your city — in Miami you’ll never book a driver currently in New York. That insight simplifies the problem enormously. Globally there are millions of riders/drivers, but a single city may have only a few thousand. Mirror that in your architecture: bundle nearby cities into a local region (“Northeast US”, “Southwest US”), give each region its own database on distinct servers in that geography, and co-locate the request-handling servers alongside the databases they query. Riders’ queries are answered by regional services (fast) hitting a local database (very fast). Near-instant responses because the system is close.

Handling failures & fault modes

Beyond server failures (crashes, solar flares flipping bits, cut power), we face network failures: cut cables, failed routers, dropped packets. Robust design plans for all of these.

Watch out — “the network is reliable” is a fallacy

One of the most dangerous assumptions in distributed systems. Always design expecting network calls to fail, be delayed, or return unexpected results.

Timeouts, retries & backoff

The most elementary hygiene. If a request is expected to take a certain time, set a timeout and give up (and retry) if it exceeds it. The worst scenario is making a request, getting an “in progress” acknowledgement, then never hearing back — the client waits forever. But a timeout that’s too short is also bad: a 3-second timeout when the server needs 4 seconds means you fail no matter what. Timeouts must be long enough to let servers respond, short enough to still serve their purpose.

Retries handle transient failures — a temporarily slow server often succeeds on retry. But a naive “retry every 5 seconds” is bad for two reasons: the server probably hasn’t changed, and requests bunch up.

Backoff + jitter — the gold standard

Backoff (often exponential): increase the wait between retries — 2s, then 4s, then 8s, then maybe give up. The first retry happens quickly (don’t make users wait for something transient), but after a couple of failures something substantial is likely wrong and needs time to recover. Jitter (randomness): without it, all clients retry in lockstep and keep colliding — “a jackhammer.” Add randomness (2.5s vs 1.9s vs longer) so retries spread across the timeline and desynchronize. In interviews, the magic phrase is “retry with exponential backoff,” and senior interviews may ask you to add jitter.

▸Worked example — why lockstep retries fail (from the video)

A service handles 2 transactions/sec, but red, green, and blue clients all fire simultaneously and fail. All retry in 5 seconds, fail again, retry again — perfectly synchronized, forever tripping the 2/sec limit. Backoff halves the request rate over time, giving the server breathing room; jitter delays each client by a slightly different random amount so successive retries also spread out. Together they kill the synchronization and let a request finally succeed. See AWS’s Timeouts, Retries, and Backoff with Jitter.

Idempotency

Retries are great — except when they have side effects. Retrying a “charge $10” request could charge the user $20 (or $2,000). The fix: make APIs idempotent — callable multiple times with the same result. Reads are naturally idempotent (an HTTP GET doesn’t change state, even if the content it returns changes). Writes are harder.

Idempotency keys for writes

Attach a unique idempotency key to the request. For a payment where a user buys one item per day, the key could be user ID + current date. Server-side, check whether a request with that key has already been processed (or is in progress) and process it only once. Friendly APIs wait for the in-flight request and return the result to all callers; less friendly ones return an error saying the request already exists — either way, no double charge.

Circuit breakers & cascading failures

Senior/staff candidates are often asked “what happens when this service goes down?” Sometimes the answer is simple (“retry until it’s back”) — but retries can create new problems. If a database goes down cold and must boot one instance at a time, a firehose of retries and angry users can pin an instance so it never starts. You can’t bring up the first instance, so you can’t recover the whole database — a thundering herd.

▸Worked example — a cascading failure trace (from the video)

Server A → Server B → database, all healthy. An admin triggers a DB snapshot; the database now runs at 50% efficiency. Server B’s timeouts start firing, its requests fail, its retries also fail (three tries, progressively longer, then give up). Server A does the same to B. The database’s degradation cascades: B goes down under the load, and restarting B doesn’t help because the database is still unresponsive and A is still hammering it. What’s needed is for A to give B a break, so B can give the database a break — and someone can notice the snapshot.

Enter circuit breakers — inspired by the electrical kind. They protect the system when calls to a dependency fail repeatedly:

CLOSEDCalls flow normally. Failures are counted.
OPENThreshold exceeded → “trip.” Requests fail immediately, no call attempted.
HALF-OPENAfter a timeout, a test request decides: close (recover) or stay open.
The three states. Tripping lets a failing dependency recover instead of being hammered — and self-heals when it returns to health.
  1. The breaker monitors failures when calling an external service.
  2. When failures exceed a threshold, the circuit trips to open.
  3. While open, requests fail immediately without attempting the real call.
  4. After a timeout, it moves to half-open.
  5. A test request determines whether to close the circuit or keep it open.
Why circuit breakers help
  • Fail fast — reject calls to failing services instead of waiting for timeouts.
  • Reduce load — stop overwhelming an already-struggling service.
  • Self-healing — automatically test recovery without full traffic.
  • Better UX — fast fallbacks instead of a hanging UI.
  • System stability — one service’s failure doesn’t spread. Put alarms on the breaker so you know when it trips.

Good places to apply them: external/third-party API calls, database connections and queries, service-to-service calls in microservices, resource-intensive operations that might time out — any network call that could fail or become slow. They’re a strong answer when an interviewer deep-dives on reliability, failure modes, or disaster recovery.

Wrap-up

07Wrapping up

Networking is the foundation connecting all components in a distributed system. The field is vast, but four areas prepare you for most interviews:

  1. Understand the basics — IP addressing, DNS, the TCP/IP model.
  2. Know your protocols — TCP vs UDP, HTTP/HTTPS, WebSockets, gRPC.
  3. Master load balancing — client-side balancing and dedicated load balancers.
  4. Plan for practical realities — regionalization and patterns for handling failures.

Networking decisions touch every part of a system — latency, throughput, reliability, security. In interviews, justify your choices against the specific requirements. These defaults are sensible, but most problems have no single right answer; the interviewer wants to see how you reason through trade-offs.

Tip — learn by watching packets flow

Reading isn’t always the best way for builders to internalize this. Capture real traffic on your own machine with Wireshark to see the whole protocol stack in action. Then simulate failures — Mac’s Network Link Conditioner (via Xcode) can inject latency and packet loss. Simulate a nasty cell connection and watch how apps respond; you’ll find surprises and a lot of bugs.

Practice

↻Active recall

Answer from memory first, then reveal. These test reconstruction, not trivia.

Q1Walk through everything that happens from typing a URL to receiving the page, naming the layer each step lives at.+

DNS resolves the domain to an IP (L7 → relies on L3 addressing). TCP three-way handshake SYN/SYN-ACK/ACK establishes the connection (L4 over L3). HTTP GET is sent (L7). Server processes and builds the response. HTTP response returns. TCP four-way teardown FIN/ACK/FIN/ACK closes it. Carry-forwards: the app can assume reliability/ordering; one “request” is many packets (latency); the connection is state both sides maintain.

Q2Your interviewer pushes you to justify UDP over TCP. What two conditions must hold, and give an example.+

(1) Latency is paramount, and (2) you can tolerate loss / out-of-order packets. Example: video conferencing drops a frame rather than retransmitting it; VoIP accepts an occasional audio hiccup instead of clogging the network with ACKs. Caveat: browsers don’t support UDP natively (outside WebRTC), so provide a TCP path for browser clients.

Q3How does TCP know a packet was lost or arrived out of order?+

On setup TCP starts a sequence and numbers each packet. Receiving 1 and 3 implies 2 is missing (ask the sender to resend); receiving 5 right after 3 means it waits for 4 before handing 5 to the application. Note the limit: TCP’s “guaranteed delivery” means the other host received it — not that it was written to disk.

Q4Why is REST the interview default, and when would you deliberately move to GraphQL or gRPC?+

REST is well understood, general, and performant enough for most systems. Move to GraphQL when the frontend changes fast or many teams query overlapping data with unpredictable shapes (fixes under/over-fetching) — but interviews usually have fixed requirements, so it’s often in the way. Move to gRPC for internal, performance-critical, network-bound service-to-service calls (binary protobuf, ~10× throughput) — not for public APIs, since browsers/external clients don’t support it and it’s harder to debug.

Q5SSE vs WebSockets — how do you choose, and what’s the stateful cost of WebSockets?+

SSE is one-directional server→client push over a single HTTP response — use it for notifications/updates over a short window or streaming AI tokens; it auto-reconnects with the last-event ID. WebSockets are bidirectional, high-frequency, persistent — use them only when you truly need two-way real-time. Their cost: the connection must stay alive for its whole lifetime (maybe an hour), which complicates deployments and failures. The pattern: terminate WS at an edge message-broker/notification service that exposes methods to internal services.

Q6Why is a Layer 4 load balancer preferred for WebSockets while Layer 7 is the default elsewhere?+

L4 routes on IP/port without inspecting content and keeps a client pinned to one server for the whole TCP session — ideal for persistent connections like WebSockets. L7 understands HTTP, can route on URL/headers/cookies and terminate HTTPS, and can fan requests across backends — great flexibility, so it’s the default for ordinary HTTP traffic. But a WebSocket can only be balanced at the initial HTTP upgrade; after that it’s a persistent TCP stream that can’t be rebalanced midstream, so L4 fits better.

Q7A database snapshot slows the DB by 50%. Trace how this can cascade, and how a circuit breaker stops it.+

The slow DB makes Server B’s requests time out; B retries (and those fail too), then A retries against B. Load compounds, B falls over, and restarting B doesn’t help because the DB is still slow and A keeps hammering. A circuit breaker on A’s calls to B trips to open after failures exceed a threshold, failing fast without calling B — giving B (and the DB) room to recover. After a timeout it goes half-open, tests one request, and closes if healthy. Alarms tell you it tripped.

Q8Why isn’t “retry every 5 seconds” good enough, and what’s the gold-standard fix?+

The server likely hasn’t recovered, and all clients retry in lockstep, repeatedly colliding against the same limit (“jackhammer”). Fix: exponential backoff (2s, 4s, 8s…) to reduce the request rate and give the server room, plus jitter (randomized delays) to desynchronize clients so retries spread across time. Pair with sensible timeouts and idempotency (idempotency keys) so retries don’t double-charge.

Q9Designing a global service, why isn’t it enough to just move a web server close to the user?+

One user request triggers many web-server↔database round trips. Moving only the web server to London shortens the user hop but leaves long hops to a distant database — so you must collocate processing and data first, then move that unit near users. Options for data that must be everywhere: partition globally (keep data where it’s most used) or replicate (write locally, replicate for fast remote reads, accepting lag). CDNs cache cacheable/static content at edge nodes near users.

Revise

≡Quick revision

A fast memory refresh — not a replacement for the main notes above.

Interview defaults

  • Transport: TCP (assumed).
  • API: REST.
  • Load balancer: L7 (L4 for WebSockets).
  • Scaling: horizontal (interviews expect it).
  • Failures: timeouts + retries + exponential backoff + jitter.

The layers

  • L3 Network: IP — routing & addressing.
  • L4 Transport: TCP / UDP / QUIC — ordering, delivery, ports.
  • L7 Application: HTTP, SSE, WebSockets, gRPC, WebRTC.
  • Each builds on and ignores the one below.

TCP vs UDP

  • TCP: connection, reliable, ordered, flow + congestion control. Overhead.
  • UDP: connectionless, best-effort, unordered, fast. “Spray and pray.”
  • UDP for streaming/gaming/VoIP; TCP for everything else.

Application protocols

  • REST: resources + verbs, JSON. Default.
  • GraphQL: client shapes the response; fixes under/over-fetching.
  • gRPC: protobuf binary, internal, fast.
  • SSE: server→client push over HTTP.
  • WebSockets: bidirectional, persistent, stateful.
  • WebRTC: peer-to-peer over UDP; A/V calling.

Must remember

  • The connection is state both sides maintain.
  • Data locality: collocate data + compute, near the user.
  • CDN = cache at edge nodes; miss → proxy to origin.
  • Idempotency keys make retried writes safe.
  • Circuit breaker states: closed → open → half-open.

Common mistakes

  • Trusting the request body (validate user IDs server-side).
  • Modeling REST as operations (/updateUser) not resources.
  • Reaching for WebSockets / WebRTC unprompted.
  • Assuming “the network is reliable.”
  • Lockstep retries with no backoff/jitter.

Study notes built from the Hello Interview guide “Networking Essentials for System Design Interviews” and its companion video walkthrough. Where the video added intuition beyond the written guide, it’s marked as an Instructor insight. One minor mismatch to note: the written guide gives Apple’s IP block as 17.0.0.0, while the video says 18 — the guide is the primary source here.