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)?