Chapter 06 / 10 · Foundations

The network is a machine too

Everything so far happened inside one box. Almost nothing you will build stays there.

The network is the bottom rung of the latency ladder, and the first place where things fail partially — a packet can simply not arrive, and nobody is obliged to tell you. Everything the Distributed Systems pathway later makes rigorous begins here as plain mechanics. Follow one HTTPS request all the way, layer by layer.

A name becomes an address

DNS first. Your process asks a resolver; on a miss the resolver walks the hierarchy — root servers, then .com, then the domain’s authoritative servers — and caches the answer for its TTL. Two engineering consequences hide in that sentence: DNS is the first cache you configure (a 5-minute TTL means failover takes up to 5 minutes; a 5-second TTL means constant lookups), and DNS is a crude but universal traffic-steering tool — return different addresses to different regions and you have routed users before a single packet reaches you.

A connection becomes possible

IP moves packets and promises nothing: loss, duplication, reordering are all allowed. TCP builds a reliable, ordered byte stream on top — but first the two ends must agree to talk: SYN, SYN-ACK, ACK. One round trip before any data. TLS (1.3) adds identity and encryption for one more round trip. Only then does the request itself travel.

clientserverDNS lookup~1 RTTTCP handshake1 RTTTLS handshake1–2 RTTRequest + response1 RTTat 150 ms per round trip, the wire is idle — the distance is the cost
Fig 3 · What a fresh HTTPS request pays before any real work happens

Notice what the diagram is really saying: the wire is mostly idle. The cost is not bandwidth — you can buy bandwidth — it is the speed of light applied several times in a row. Hence the single most valuable network optimisation in ordinary backends: reuse connections. Keep-alive and connection pools pay the handshake tax once and amortise it over thousands of requests; a service that opens a fresh TLS connection per call has tripled its latency floor by choice.

Reliability, and what it costs

TCP numbers every byte, acknowledges what arrives, retransmits what does not, and paces itself twice over: flow control (do not drown the receiver) and congestion control (do not drown the network — start slow, speed up until loss says stop). Two consequences matter to you. A new connection cannot use full bandwidth immediately (slow start — another argument for reuse). And because the stream is strictly ordered, one lost packet stalls everything behind it: head-of-line blocking. That single defect explains a decade of HTTP evolution:

VersionTransportMultiplexingHead-of-line
HTTP/1.1TCPnone — one request at a time per connectionat the app: browsers open ~6 connections to fake it
HTTP/2TCPmany streams on one connectionmoved down: one lost packet stalls all streams
HTTP/3QUIC (UDP)many independent streamsper-stream only; also 1-RTT combined handshake

The socket boundary

One level down, the API keeps a final surprise: TCP is a stream of bytes, not of messages. A single read() may return half a message or three glued together, and a large write() may send only part of your buffer. Deciding where one message ends is your protocol’s job — a length prefix, a delimiter, or a format like HTTP that carries its own framing. Every “it only breaks under load” parsing bug traces back to this paragraph.

Where it bites

  • No timeout on a network call — you have volunteered to wait forever; the OS default is not your SLA.
  • Assuming one read() = one message. It equals one some bytes.
  • Fresh connection per request — the handshake tax, paid maximally.
  • Measuring throughput over a long fat link and blaming bandwidth — throughput on one connection is bounded by window ÷ round-trip time; distance was the problem.