node.js response.write(data)当数据量很小时需要很长时间

我注意到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的networking标签,增加/差异全部来自接收(另一方面,两者都是16ms)。

我做了以下修改来解决这个问题,这样两个case都有16ms的响应时间:

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

我已经通过node.js 文档查看,但到目前为止还没有find相关的信息。 我猜这与缓冲有关,但是可以在write()end()之间抢占node.js?

更新:

这在Linux上的v0.10.1上进行了testing。

我试图偷看到源代码 ,并确定了2path之间的差异。 第一个版本有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); 

第二个好的版本只有一个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); 

仍然不确定是什么让第一个版本不能很好地处理较小的响应大小。

简短的回答:

您可以显式设置 Content-Length 标题。 从200ms到20ms,响应时间会缩短。

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

事实:

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

然后我用wireshark来捕获服务器端的networking包。 以下是一个典型的结果:

对于小content

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

对于更大的content

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

可能的解释:

如果未设置Content-Length头,则数据将以“分块”模式传输。 在“分块”模式下,服务器和客户端都不知道数据的正确长度,所以客户端会等待(200ms),看看是否有下面的包。

但是,这个解释又提出了另外一个问题: 为什么在更大的 content 情况下,客户端没有等待200ms(而是等待大约50ms)?