Reputation: 43
Keep-alive is supposed to speed up the site.
However, when I run this dead simple server in chrome (localhost:8080), I get these loading times:
around 100 ms with the "Connection: close" header (i.e. with setHeader line uncommented)
around 400 ms with the standard keep-alive enabled.
What am I doing wrong ? Can anybody reproduce my result ?
I have been banging my head for the last 2 days on this.
var fs = require('fs')
// preparing 50 2k files ...
var a = [], txt = '/*\n' + 'x'.repeat(2000) + '\n*/'
for (var i = 0; i < 50; i++) {
var name = '/test' + i + '.js'
fs.writeFile(__dirname + name, txt)
a.push('<script src="' + name + '"></script>')
}
fs.writeFile(__dirname + '/index.html', a.join('\n') + '\nhello world')
var serve = function (req, res) {
if (req.url === '/favicon.ico') {
res.statusCode = 404; return res.end()
}
var pth = req.url + (req.url.match(/\/$/) ? 'index.html' : '')
var s = fs.createReadStream(__dirname + pth)
res.on('finish', function () { console.log('done', req.url) })
// THIS IS THE KILLER LINE. Just uncomment and restart the server.
// on my system, the page loads 4 times FASTER
// res.setHeader('Connection', 'close')
res.statusCode = 200; s.pipe(res)
}
require('http').createServer(serve).listen(8080)
EDIT
for clarity, the behaviour is the same when using a standard express server. The following server code will yield the same results (on my system, at least)
// express server code
var express = require('express')
var app = express()
var closeConnection = function (req, res, next) {
res.setHeader('Connection', 'close'); next()
}
// THIS IS THE KILLER LINE. Just uncomment and restart the server.
// on my system, the page loads 4 times FASTER
// app.use('*', closeConnection)
app.use(express.static(__dirname))
require('http').createServer(app).listen(8080)
Upvotes: 3
Views: 1476
Reputation: 106
This seems to be due to Nagle's algorithm that is active by default. This causes a delay before sending TCP packets, waiting for possibly more data to be sent in one packet to avoid too small packets.
Because closing a connection causes the pending packet to be sent immediately, this doesn't affect latency when not using keep-alive connections.
As explained in this answer, Nagle's algorithm can be disabled like this:
server.on("connection", function (socket) {
socket.setNoDelay(true);
});
This should fix the latency issue. Note that it can slow down the transfer rate if you’re not handling the buffering yourself and sending a lot of small packets.
I noticed that the problem occurs when a response is piped (causing chunked transfer-encoding to be used) (and even with a Content-Length
header), but not when sending complete responses at once with res.json()
for example.
Also, it seems that this issue is much less present since Node.js 8.0.0. Disabling Nagle's algorithm still has a positive effect in my case though.
Upvotes: 2
Reputation: 48387
There is a huge difference between what's happening in your server and what is happening across the internet, although I am a little surprised at the metrics you have reported here. You didn't say how you captured the metrics nor the content generation time. We can assume the latter is under 100 mseconds, suggesting that something very weird is happening on your loopback interface, or that node.js is doing something very weird in this case, or possibly the scheduling of the browser task is blocking the webserver task.
Certainly if you are publishing pages needing more than a single file to render, and are passing data across the internet, disabling keepalives should lower your server load and CPU usage, but increase the page load times.
I would suggest you start adding in other components and see when the expected state of affairs resumes. I would start by running the client on a separate machine / running multiple clients.
Upvotes: 1