Tied to Mission: Backend Depth — the networking phase, and the resource-exhaustion latency spike the baseline assessment surfaced.
Open a browser devtools network tab and hit an API host you haven't talked to yet. The first request takes noticeably longer than the ones right after it, even though the server is doing the exact same work each time. Nothing about the request or the response changed. What changed is everything that had to happen before the request could even be sent.
An RTT (round-trip time) is the time for one message to travel to the other side and its acknowledgment to travel back. Before a single byte of your actual HTTP request goes out over a fresh connection, two setup steps happen, each spending RTTs of their own:
Add it up and a brand-new HTTPS connection can cost multiple round trips of pure setup latency before your GET or POST is even on the wire — on top of the RTT the request and response themselves need. None of that shows up as "server processing time." It's paid entirely in the network layer, invisibly, every time a new connection has to be established.
HTTP keep-alive means the TCP connection (and its TLS session) stays open after the first request completes, so it can carry the next request too. A request sent over an already-open connection skips both handshakes entirely — zero extra round trips before it goes out. That's the whole reason the second request to the same host feels instant compared to the first: the first request paid for the pipe, everything after it just uses the pipe.
The same math applies when your app server calls a downstream API or a database, not just when a browser calls you. A connection pool is a set of already-established connections an app keeps warm and hands out to whichever request needs one next, instead of opening a new connection per call. As long as a pooled connection is available, a backend-to-backend call pays zero extra handshake RTTs — same as browser keep-alive.
If the pool is sized too small for the concurrency you're actually seeing, or keep-alive is disabled or timing out too aggressively, requests beyond pool capacity have no warm connection to borrow. They open a fresh one instead — paying the TCP+TLS handshake tax again, on every burst. The downstream service's own processing time hasn't changed at all. What changed is that connection setup overhead is now happening on the hot path, exactly the shape of a "latency spike from resource exhaustion": it looks like the dependency got slower, but the actual bottleneck is upstream of it, in how many connections are available to reuse.
Pick any HTTPS host and run curl -w "connect: %{time_connect} appconnect: %{time_appconnect} total: %{time_total}\n" -o /dev/null -s https://example.com twice in a row without -v forcing a new connection each time — then run it again reusing a connection via curl --keepalive-time 60 https://example.com https://example.com (or just open the same page twice in a browser devtools Network tab and compare the timing breakdown for "Connecting" and "TLS" on the first request versus a later one on the same host). Watch time_connect and time_appconnect shrink to near zero once a connection is reused.
"High Performance Browser Networking" by Ilya Grigorik, free at hpbn.co — see the "Building Blocks of TCP" and "Transport Layer Security (TLS)" chapters for the handshake mechanics this lesson simplifies, and the HTTP chapters covering persistent connections for how keep-alive and connection reuse work in practice.
Want to go deeper on TLS 1.3's 0-RTT resumption, or how connection pool sizing actually gets tuned for a real service? Ask directly — that's what this curriculum is for.