NodeJS的高延迟

这个问题特别针对Nodejitsu,但类似的效果似乎发生在其他VPS上。 我有一个使用socket.io的实时游戏,有一件事我注意到,偶尔服务器会在响应之前等待过多的时间。 如果在该时间段内发送了多个请求,则它们的行为就好像它们已经全部排队并一次处理。 我怀疑它与共享的硬件上其他用户的存在有着模糊的关系(就像任何VPS一样)。

无论如何,要testing这个(并确保它不是由于我的游戏的代码),我build立了一个最小的testing用例:

express = require('express') http = require('http') app = express() server = http.Server(app) io = require('socket.io').listen(server) io.sockets.on('connection', function(sock){ sock.on('perf', function(data, cb){ cb([Date.now()]); //respond with the current time }) }) app.get('/', function(req, res){ res.header("Access-Control-Allow-Origin", "*") res.header("Access-Control-Allow-Methods", "HEAD,GET,PUT,POST,DELETE") res.header("Access-Control-Allow-Headers", "X-Requested-With") res.end(JSON.stringify([Date.now().toString()])); //http equivalent of perf function }) server.listen(process.env.PORT || 6655, function(){ console.log('listening now') }) 

我有一个简单的空白的HTML页面与socket.io将周期性地发送一个perf事件和时间多less时间的callback触发。 它仍然显示相同的事情:

显示滞后钉的图表

请注意,长度代表时间量的平方根,而不是线性数量。

而不是依靠socket.io,我使用XHR做类似的测量当前的响应时间,结果是非常相似的,很多低延迟响应(虽然比预期更高的基准比websockets),偶尔似乎堆积的尖峰。

奇怪的是,如果你在多个浏览器窗口和不同的浏览器中打开它,似乎在不同的浏览器之间存在关联(事实上它在一些服务器上完全不存在或者不那么频繁)似乎暗示它一个服务器端现象。 但是,某些浏览器会出现延迟高峰,而其他浏览器则不会,而且同一会话的两个Chrome窗口看起来几乎是完全相同的,这表明这是本地发生的事情(每台计算机或每个浏览器,networking明智的)。

从左到右:Chrome隐身,Chrome(普通),Firefox,Chrome(常规)

四个窗口上的图表

无论如何,这一直困扰着我好几个月,我真的很想知道是什么原因造成的,以及如何解决这个问题。

我假设你检查,如果你有一个CPU或RAM的问题。

唯一能够以“令人惊讶”的方式减慢节点的是垃圾收集器 – 试着用--trace*来运行你的节点来看看发生了什么。 (请参阅node --v8-options 。)

我个人认为,你没有发现任何东西,因为 – 那就是我的感觉 – 这个问题是在别的地方。

有了500毫秒的完美延迟我假设你有一个数据包丢失。 你可以检查ifconfig是否是一个普遍的问题,然后tcpdump的数据包,看看他们是否重新发送。

我知道这可能听起来很奇怪,但是你认为这不是节点的问题,而是操作系统的设置。 你有没有检查你的文件句柄以及操作系统显示给套接字的连接数量? 你是否也确保在操作系统中的套接字超时足够低? 我遇到了与其他代码类似的声音性能问题,它原来是操作系统,而不是代码。 同时检查包并查看它在套接字上打开了允许的连接。 我没有看过节点代码,但遇到了与java中的http客户端库类似的问题。 应用程序刚刚备份,这只是一个连接数量的configuration问题。

你看到这个的原因是因为Nagle的algorithm。 这是一种在I / O上使用的algorithm,可以caching数据一段时间,然后发送更大的数据块。 它被用来保存你的传输(在套接字中)。 你可以在http://en.wikipedia.org/wiki/Nagle's_algorithm看到更多的信息

要禁用Nagle的algorithm(当你想尽可能快地发送很多小请求的时候是很好的),你可以使用socket.setNoDelay(true); 如果你使用net.Socket()。 在socket.io的情况下,我相信Nagle默认已经禁用Websockets,但不一定是其他协议。 我build议使用node.js的net.Sockets运行一个testing,禁用Nagle,看看你得到了什么。