Skip to content

client: set TCP_NODELAY on the default connector - #7

Merged
aviramha merged 1 commit into
mainfrom
aviram/client-tcp-nodelay
Aug 5, 2026
Merged

client: set TCP_NODELAY on the default connector#7
aviramha merged 1 commit into
mainfrom
aviram/client-tcp-nodelay

Conversation

@aviramha

@aviramha aviramha commented Aug 5, 2026

Copy link
Copy Markdown
Member

Draft, against our fork's main. Branched from fork/main, which is level with upstream kube-rs/kube and keeps the Portforwarder::take_stream patch that mirrord depends on.

What

impl TryFrom<Config> for ClientBuilder builds the connector with HttpConnector::new() and enforce_http(false), but never set_nodelay(true). Every client built that way runs with Nagle's algorithm enabled.

Why

Requests are small and each waits for its response, which is the pattern Nagle delays. It matters most for long-lived streams carried over the connection: a request/response protocol running inside a port-forwarded stream stalls on delayed ACKs.

mirrord reaches its in-cluster agent over Api::portforward, so a sequential protocol tunnelled through that stream pays the stall. kubectl does not show this, because it sets the option on its own connections.

Measurement

Measured in mirrord, whose agent connection is a port-forwarded stream, with a workload issuing sequential requests over it:

request p50 intproxy send->reply p99
unfixed 88.5 / 98.2 ms 41,349 / 41,417 us
with set_nodelay 39.8 / 40.9 ms 1,258 / 1,119 us

~2.3x lower latency and ~33x lower tail. The 41 ms figure is the delayed-ACK timer.

The effect is concurrency-dependent, as expected for this mechanism: the stall needs the connection to fall idle between exchanges, so the gain is largest at low concurrency and fades as concurrent traffic keeps the connection busy and ACKs ride along with data.

Risk

One line, and it only disables an optimisation that trades latency for fewer packets. Applications sending many tiny writes in sequence will emit more packets. For an API client whose traffic is request/response that is the right trade.

The default client stack builds an HttpConnector without disabling Nagle's
algorithm. Requests are small and each waits for its response, which is the
pattern Nagle delays.

It is most visible on long-lived streams carried over the connection. A
request/response protocol running inside a port-forwarded stream stalls on
delayed ACKs, adding tens of milliseconds to a fraction of its exchanges.
@aviramha
aviramha marked this pull request as ready for review August 5, 2026 11:43
@aviramha
aviramha merged commit 6cbb2e8 into main Aug 5, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant