node.js response.write(data)在数据大小很小的情况下花费很长时间

时间:2013-05-24 01:49:27

标签: node.js

我注意到了node.js中以下代码性能的奇怪行为。当content的大小为1.4KB时,请求的响应时间大约为16ms。但是,当content的大小仅为988字节时,请求的响应时间会更长,大致 200ms

response.writeHead(200, {"Content-Type": "application/json"});
response.write(JSON.stringify(content, null, 0));
response.end();

这似乎不直观。查看Firebug的网络标签,增加/差异全部来自接收(另一方面等待是两个16ms)。

我做了以下更改来修复它,以便两种情况都有16ms的响应时间:

response.writeHead(200, {"Content-Type": "application/json"});
response.end(JSON.stringify(content, null, 0));

我查看了node.js doc,但到目前为止还没有找到相关信息。我的猜测这与缓冲有关,但node.js可以在write()end()之间抢占吗?

更新

这是在Linux上的v0.10.1上测试的。

我试图查看source,并确定了2路径之间的区别。第一个版本有2个Socket.write调用。

writeHead(...)
write(chunk)
  chunk = Buffer.byteLength(chunk).toString(16) + CRLF + chunk + CRLF;
  ret = this._send(chunk);
    this._writeRaw(chunk);
      this.connection.write(chunk);
end()
  ret = this._send('0\r\n' + this._trailer + '\r\n'); // Last chunk.
    this._writeRaw(chunk);
      this.connection.write(chunk);

第二个好的版本只有1个Socket.write调用:

writeHead(...)
end(chunk)
  var l = Buffer.byteLength(chunk).toString(16);
  ret = this.connection.write(this._header + l + CRLF +
                              chunk + '\r\n0\r\n' +
                              this._trailer + '\r\n', encoding);

仍然不确定是什么原因导致第一个版本在响应量较小时效果不佳。

1 个答案:

答案 0 :(得分:9)

简答:

您可以明确设置 Content-Length 标头。它会将响应时间从200毫秒减少到20毫秒。

var body = JSON.stringify(content, null, 0);
response.writeHead(200, {
    "Content-Type": "application/json",
    'Content-Length': body.length
});
response.write(content);
response.end();

事实:

经过几次实验后,我发现,如果 content 足够小(在我的情况下,小于1310字节),单个MTU到继续,响应时间约为200ms 。但是,对于大于该值的任何content,响应时间大约为20毫秒。

然后我使用wireshark来捕获服务器端的网络包。以下是典型结果:

对于小content

  • [0000ms] response.write(content)
  • [0200ms]收到客户
  • 的ACK包
  • [0201ms] response.end()

对于较大的content

  • [0000ms] response.write(content) //发送第一个MTU
  • [0001ms]发送第二个MTU
  • [0070ms]从客户
  • 收到ACK包
  • [0071ms] response.end()

可能的解释:

如果未设置Content-Length标头,则数据将以“Chunked”模式传输。在“Chunked”模式下,服务器和客户端都不知道数据的确切长度,因此客户端会等待(200ms)以查看是否有任何后续软件包。

然而,这个解释提出了另一个问题:为什么在较大的 content 情况下,客户端没有等待200毫秒(相反,它只等了大约50毫秒)?< /强>