DNS to keep-alive
Thirteen things happen.
Only one of them is your code.
A single HTTP request, from resolving a name to reusing the socket — ordered by when rather than by which layer owns what. The useful question at every step is not what transforms what, but what is already true at that moment: your handler is running and the body has not arrived; bytes are queued and none of them have reached the network.
13
Steps
4
Projections
13
Figures
v22.22.2
Measured on
res to the last byte
You get the object first.
Everything else is decided for you.
The answer travelling the other way — from the res Node had
already built before your handler was entered, to the socket going back in a pool. The
useful question here is not what you wrote, but what was committed the moment you wrote
it: the framing you never chose, the queue the bytes are actually in, and the event that
says sent while the client has read nothing.
11
Steps
4
Projections
11
Figures
v22.22.2
Measured on
One name, four things that are not a DNS client
recorded run
Measured against registry.npmjs.org: 20.28 ms cold, 16.1 ms warm, 1.7 ms via
resolve4, which saw 12 A records with a 129-second TTL. The pool-slot occupancy is drawn from UV_THREADPOOL_SIZE rather than instrumented.Three legs, all of them before your code
recorded run
The two timings are measured — 2.28 ms to registry.npmjs.org:443 and 0.96 ms over loopback — as is the 4,096-deep accept queue, read from
/proc/sys/net/core/somaxconn. The three legs are drawn from the protocol; a Node process cannot see individual segments.One round trip, and plaintext above it
recorded run
Both handshakes are measured against a local server with a 803-byte self-signed certificate, so the numbers are the crypto rather than the network. The per-leg breakdown is the protocol's, not an instrumented trace.
One request, becoming bytes
schematic
Schematic below the socket. The 138 bytes and the 130/8 head-body split are captured from a real
http.request(), and the 16,384-byte send buffer is this machine's tcp_wmem default — but segment counts and MSS are modelled, because nothing in a Node process can observe them.One byte is enough to wake the loop
schematic
Schematic. The buffer size and the accept queue are this machine's real settings, but the occupancy shown at each stage is modelled — no API in Node exposes how full a kernel receive buffer is, which is the point the diagram is making.
One read, stage by stage
recorded run
The four stages are the code path in
uv__read and StreamBase::EmitRead. A 192 KB body arrived in 4 reads of 65,536, 62,517, 65,536, 3,072 bytes, drawn against this machine's 131,072-byte tcp_rmem default. The refill between cycles is the one modelled part.One head, callback by callback
recorded run
Every byte offset is taken from the captured 138-byte request: the request line ends at 30, the head at 130. The callback names are llhttp's API rather than a measurement — what is measured is which bytes each one covers.
One handler, ahead of its own body
recorded run
Every timestamp is from one recorded run in which the probe wrote the head, waited 120 ms, then sent the body. A slow client produces the same shape without being asked.
One rejected push, all the way to TCP
recorded run
The occupancy figures are from an 8 MB body the handler deliberately ignored: 128,000 bytes in
req, 0 in the socket, socket paused true. The window shrinking is the one part not directly observable from Node — it is inferred from the sender stopping.One false, three possible queues
recorded run
Both halves are measured: the client-side
outputData figures from an http.request() written to before its socket arrived, and the socket-queue figures from a 1 MB write to a client that refused to read. The libuv and kernel queues below are stated, not measured — nothing in a Node process can see them.One response, becoming bytes
recorded run
The 161 response bytes and the chunk framing are captured from a real server. The per-stage split of when each byte is written is derived from the framing rather than instrumented.
One promise, resolving twice
schematic
Schematic throughout. This half happens in a browser and nothing in a Node process can observe it. The ordering is the fetch standard's, not a measurement — it is the one diagram here with no recorded numbers behind it.
One socket, three requests
recorded run
All of it is from one recorded run of 3 requests through a single keep-alive agent: same local port every time, 2 handshakes avoided, 10.35 ms then 0.78 ms.