-
Notifications
You must be signed in to change notification settings - Fork 30k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net: enable TCP_NODELAY by default on all platforms #906
Comments
I may have to dig deeper here. Windows for example doesn't default to TCP_NODELAY either, so it seems questionable if we would rely in platform defaults like the issue implies. |
+1 seems like a bug, my initial thought was the docs should be changed but it seems like nodelay is highly recommended as default for today's networking. I would hazard a guess that os platforms not already doing this are playing it safe where as iojs can be more reactive to current practice. |
Yes, Nagle's algorithm isn't really beneficial in today's latency-limited networks. I wonder if it's possible to test from JS whether it is enabled on a target host. |
+1 |
+1 from me too, I'd love to see this. |
The fact that the documentation says that TCP_NODELAY is enabled by default seems like a documentation bug to me. As far as I know, that has never been true. I'm on the fence as to whether it's a good idea to enable it by default. I'd be more comfortable +1'ing that if I had more faith in the net module's capabilities of batching writes. That's not to say I object, just that I'm not sure if defaulting to TCP_NODELAY is an unequivocally good thing. |
If we go through with it enabling it everywhere, we need an mechanism for the users to disable it globally too. I think ideally on a per-process basis, maybe something like The reason is simple: With |
I think regardless if we enable it by default or not, a While it can be set at kernel-level, I think controlling it on a per-program basis is preferred. For example, nginx has the option to set it per-server. |
@bnoordhuis I wonder if adding a |
A Or would it be possible to apply |
I generally dislike any type of "global" setting. You wanted to speed up your http server but without realizing the database driver just got slower. Node should pick reasonable defaults (so maybe switch it on by default), behave consistently on all platforms (fix windows and/or aix), and be easy to configure (maybe setNoDelay is too difficult for http servers). Let's keep bikeshedding withing this parameter space. |
As a first step, I'm trying to verify that "use strict";
const net = require("net");
const port = 4000;
let timeClient, timeServer;
function time() {
let hrtime = process.hrtime();
return hrtime[0] * 1e9 + hrtime[1];
}
net.createServer(function(socket) {
socket.setNoDelay(true); // correct?
timeServer = time();
socket.write("\0");
socket.on("data", function () {
console.log("Client -> Server " + ((time() - timeClient) / 1000).toFixed(0) + "µs");
});
}).listen(port);
setInterval(function() {
let socket = new net.Socket();
socket.setNoDelay(true); // correct?
socket.on("data", function () {
console.log("Server -> Client " + ((time() - timeServer) / 1000).toFixed(0) + "µs");
timeClient = time();
socket.write("\0");
socket.end();
}).connect(port);
}, 200); Is this the correct usage? @evanlucas maybe you can have a look, as you've dealt with these socket options recently. edit: updated to measure both delays. also: i fail at math, it's µs :) |
@silverwind |
Right, that should fix the client part. I'll focus my tests on the server part now. |
Wasn't this issue brought up before? I can't remember if that was fixed already or if it's still being worked on ... EDIT: Still in progress.... #880 |
Much better test for the server: https://gist.github.com/silverwind/a7a702e05b3a69578f58 I see single byte packets on the wire now, so it's definitely working. @bnoordhuis care to elborate about your concerns about batching? I've yet to read through the code, but I assume TCP_CORK is involved? Any suggestion on how to verify/test the batching? |
@silverwind Not TCP_CORK, just smart coalescing of writes in libuv or io.js. Here's an example of what I mean: var socket = /* ... */;
function f() { socket.write('x'); }
setImmediate(f);
setImmediate(f); The two writes should ideally be folded into a single write(2) system call (and therefore a single TCP packet) but io.js is currently not nearly smart enough to pull that off. |
One more thing I noticed in the test is that on the receiving end, the |
That's expected. I think that if you run |
Current status: I still intend to flip the switch here if there's no performance impact in doing so. Testing for it is the hard part. |
@silverwind Is this still something that's being worked on? |
Not currently working on it but if anyone wants to benchmark with nodelay, the patch in nodejs/node-v0.x-archive#9235 is a good start. |
@silverwind Should this be closed? Or stay open and maybe tagged with |
I think it's definitely something we should strife to add. We just need to assess that it doesn't regress throughput too much, maybe by adding a benchmark to showcase the difference. |
@nodejs/benchmarking could we run an acmeair tests on the benchmark machine with this enabled? Would that be sufficient? |
I can look at running acmeair with nodelay set. Is this still the patch to be used ?
|
cc @silverwind |
Yes, that should be it. Keep in mind that the OS might already default to having it enabled, so you likely need to disable it in |
The current benchmarking setup only supports Linux x86. Does anybody on this discussion know if TCP_NODELAY is enabled/disabled by default on this platoform. I can search for the answer, but if anybody already know based on the past discussion it would same me some time. |
@mhdawson TCP_NODELAY is disabled by default on Linux and there is no sysctl to override that, as far as I'm aware. A quick check of net/ipv4/tcp.c seems to confirm that. |
ping @mhdawson ^ |
Applied this patch: https://github.com/mhdawson/io.js/commit/eb83dc31db2f68a67473dc6fdbcd521994d2b446.patch Initial results BEFORE CHANGE: https://ci.nodejs.org/view/All/job/benchmark-footprint-experimental-TCP_NODELAY/1/
AFTER CHANGE: https://ci.nodejs.org/view/All/job/benchmark-footprint-experimental-TCP_NODELAY/5/consoleFull
assuming that it was off by default and that my patch properly turns it on where it matters, it does not seem to have affected latency or throughput to a noticeable degree. More runs would like be needed to confirm. |
@mhdawson what packet size are you using in these tests? Can you try to vary them? |
Do you have the command to vary the packet sizes from the command line ? If so I can launch some runs with the values you'd like. |
On Linux, it should be |
Should this remain open? |
I'd say so. |
I just stumbled upon this and I know that using the NAGL algorithm has a huge impact in case you send very tiny buffer chunks and wait for the result as done in the node_redis benchmarks. Results
So I definitely think this is a good idea. I do not know of any negative side effects but I only checked this for |
@BridgeAR do you think you could come up with a test that verifies that it's enabled? This was the part that I was struggling with last time. Other than that, the change itself to enable it should be just setting the socket option. |
ping @BridgeAR |
Over a year with no update, so I'm going to close this. |
Just saw nodejs/node-v0.x-archive#9235 and this might be a good addition for platform consistency for us too. I'm just not sure if the proposed patch is the best place to put the call.
The text was updated successfully, but these errors were encountered: