Description
Prior art
Issues
This has been discussed before without any conclusion:
- 2015-2018 in net: enable TCP_NODELAY by default on all platforms #906
- 2015 in Default nodelay value needs to be set for all sockets. node-v0.x-archive#9235
Relatedly #906 and the discussion there has been mentioned:
- Recently, in the beginning of 2020, in http: Add noDelay to http.request() options. #31539 as well as docs: Reword socket.setNoDelay() #31541
Commits
The setNoDelay()
option was originally introduced in 2009 in e0ec003 and was shipped in v0.1.12
Wider context
curl
In 2016 curl changed it's behavior from being like the one in Node.js to instead be setting TCP_NODELAY
by default. See curl/curl@4732ca5 which was released in v7.60.2.
Motivation from commit:
After a few wasted hours hunting down the reason for slowness during a TLS handshake that turned out to be because of TCP_NODELAY not being set, I think we have enough motivation to toggle the default for this option. We now enable TCP_NODELAY by default and allow applications to switch it off.
npm modules
agentkeepalive
The agentkeepalive module, with ≈3.5 million weekly downloads, pushes its non-configurable default of socket.setNoDelay(true)
as one of its major benefits.
It was added in node-modules/agentkeepalive@c92f5b5 and references a Scaling node.js to 100k concurrent connections! blog post to explain it.
Used by eg. eggjs/egg, cnpm/cnpmjs.org, pubnub/javascript, googlemaps/google-maps-services-js, node-modules/urllib
superagent
In 2017 the superagent module, also with ≈3.5 million weekly downloads, merged ladjs/superagent#1240 and made socket.setNoDelay(true)
its non-configurable default, largely arguing that there was no need for any buffering.
Other npm modules
Many modules relies on the default behaviour of Node.js, and thus does not disable any delay by default.
A quick glance puts all of these in that category, none of them directly calls setNoDelay
(though they could eg. use something like the agentkeepalive module): axios
, bent
, got
, node-fetch
, request
, unfetch
Documentation
The Node.js documentation of setNoDelay
was recently updated: #31541
Before that update, my perception is that many believed that Nagle's algorithm wasn't enabled by defaults, as proved by eg. the conversation in superagent: ladjs/superagent#1240
Proposed change
To make TCP_NODELAY
/ setNoDelay
the default for HTTP(S) 1.x + maybe introduce a setDelay()
method to disable it.
Probably in a new major version, as it can be a breaking change in some contexts.
Why
I believe that the expectations has changed since setNoDelay
was introduced in 2009.
With eg. curl now setting it by default I believe most expects TCP_NODELAY
/ setNoDelay
to be set by default and thus Nagle's algorithm to be disabled by default.
The confusion the current default seems to make in issues like ladjs/superagent#1240, especially before #31541, supports that.
Also: As TCP_NODELAY
/ Nagle's algorithm is implemented at an OS level this can also have a minor added benefit of improved cross-platform behavior, as no platform will add a delay.
Benefits
- Better comply with general expectations among developers
- Move with the times and in sync with other major players like
curl
- In some cases better performance due to no delay. Especially so in real time scenarios.
Downsides
- Possibly increased bandwidth use
- Possibly decreased performance due to bandwidth saturation
- As any change of a default on this level, it breaks the expectations of those who knowingly wants the current default behaviour.
My background
I have no expertise in the implementation of Nagle's algorithm or the TCP-stack in general, though I became intrigued by this and did my research and through that research I found that most were either confused by this or had already changed the default for this.
Comments, suggestions, feedback and link to other discussions would be most helpful.