我注意到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();
Run Code Online (Sandbox Code Playgroud)
这似乎不直观.查看Firebug的网络标签,增加/差异全部来自接收(另一方面等待两者都是16ms).
我做了以下更改来修复它,以便两个案例都有16毫秒的响应时间:
response.writeHead(200, {"Content-Type": "application/json"});
response.end(JSON.stringify(content, null, 0));
Run Code Online (Sandbox Code Playgroud)
我查看了node.js 文档,但到目前为止还没有找到相关信息.我的猜测这与缓冲有关,但是node.js可以在write()和之间抢占end()吗?
更新:
这是在Linux上的v0.10.1上测试的.
我试图窥视源并确定了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);
Run Code Online (Sandbox Code Playgroud)
第二个好的版本只有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);
Run Code Online (Sandbox Code Playgroud)
仍然不确定是什么让第一个版本在响应尺寸较小时效果不佳.
简短回答:
您可以显式设置 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();
Run Code Online (Sandbox Code Playgroud)
事实:
经过几次实验后,我发现如果 content 单个MTU继续运行的时间足够小(在我的情况下,小于1310个字节),响应时间大约为200ms.但是,对于content大于该值的任何值,响应时间大约为20ms.
然后我使用wireshark来捕获服务器端的网络包.以下是典型结果:
对于小content:
response.write(content)response.end()更大的content:
response.write(content)//发送第一个MTUresponse.end()可能的解释:
如果Content-Length未设置标头,则数据将以"Chunked"模式传输.在"Chunked"模式下,服务器和客户端都不知道数据的确切长度,因此客户端将等待(200ms)以查看是否有任何后续包.
然而,这个解释提出了另一个问题:为什么在更大的 content 情况下,客户端没有等待200ms(相反,它只等待大约50ms)?