How Node.js http.Agent KeepAlive Reduces API Latency
In high-throughput Node.js applications, making frequent HTTP
requests can introduce significant network latency due to the overhead
of repeatedly establishing TCP connections. Enabling the
keepAlive option in Node.js’s http.Agent
addresses this bottleneck by reusing existing TCP connections for
subsequent requests instead of closing them after a single use. This
article explains how TCP connection reuse works, why it eliminates
costly network handshakes, and how configuring keepAlive
optimizes API performance.
The Cost of New Connections
By default, Node.js’s default HTTP agent does not reuse connections
(keepAlive: false). This means every outbound HTTP request
initiates a brand-new TCP connection. For every request, the client and
server must perform a TCP three-way handshake (SYN, SYN-ACK, ACK). If
the connection is secured with HTTPS, it also requires a TLS handshake,
which adds several more round-trips of data exchange before any actual
application data is sent.
In high-throughput APIs making hundreds or thousands of external
requests per second, this process introduces severe latency.
Furthermore, rapidly opening and closing connections can lead to
ephemeral port exhaustion on the client system, as closed sockets remain
in a TIME_WAIT state for several minutes.
How keepAlive Eliminates Handshakes
When you configure keepAlive: true on an
http.Agent (or https.Agent), the agent
maintains a pool of persistent connections.
Here is how the workflow changes:
- First Request: The client establishes a new TCP and TLS connection to the destination server. The request is sent, and the response is received.
- Connection Preservation: Instead of closing the socket when the response ends, the agent keeps the socket open and places it into an idle pool.
- Subsequent Requests: When the application initiates a new request to the same host and port, the agent retrieves the idle socket from the pool and immediately transmits the data.
By reusing the socket, the application completely bypasses the TCP and TLS handshakes for all subsequent requests. This reduces the latency of secondary requests by one to three round-trip times (RTTs). Additionally, it bypasses the TCP “slow start” algorithm, allowing data to be transmitted at optimal speeds immediately.
Key Configuration Properties
To implement keepAlive effectively, you must configure
the agent with parameters that match your API’s traffic patterns:
const http = require('http');
const keepAliveAgent = new http.Agent({
keepAlive: true,
maxSockets: 100,
maxFreeSockets: 10,
timeout: 60000 // 60 seconds
});keepAlive(Boolean): Enables or disables connection persistence. Set this totrue.maxSockets(Number): The maximum number of concurrent sockets allowed per host. In high-throughput systems, increasing this value prevents requests from queuing waiting for an available socket.maxFreeSockets(Number): The maximum number of idle sockets to keep open in the free pool. Setting this too low will cause the agent to close sockets prematurely; setting it too high may waste system memory and server resources.timeout(Number): Specifies the active socket timeout in milliseconds. This should align with the keep-alive timeout of the destination server to prevent sending requests over sockets that the server is actively closing.
By reducing connection overhead, conserving system ports, and
avoiding renegotiation delays, enabling keepAlive in
Node.js is one of the most impactful configuration changes you can make
to optimize downstream API latency.