6

node.js での次のコードのパフォーマンスの奇妙な動作に気付きました。のサイズcontentが 1.4KB の場合、リクエストの応答時間は約 16ms です。ただし、 のサイズcontentがわずか 988 バイトの場合、リクエストの応答時間は奇妙に長くなり、約200 ミリ秒になります。

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

これは直感的ではないようです。Firebug の net タブを見ると、増加/差異はすべて受信によるものです (一方、待機は両方とも 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 でテストされました。

ソースを覗いてみたところ、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);

2 番目の適切なバージョンには、Socket.write 呼び出しが 1 つだけあります。

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

最初のバージョンが小さい応答サイズでうまく機能しない理由はまだわかりません。

4

1 に答える 1

9

簡潔な答え:

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();

事実:

いくつかの実験の後、単一のMTUを実行するのに十分小さい (私の場合 content は 1310 バイト未満) 場合、応答時間は約 200ms になることがわかりました。ただし、contentその値よりも大きい場合、応答時間は約 20 ミリ秒になります。

次に、Wireshark を使用してサーバー側のネットワーク パッケージをキャプチャしました。以下は典型的な結果です。

小さい場合content:

  • [0000ms]response.write(content)
  • [0200ms]クライアントからACKパッケージを受信しました
  • [0201ms]response.end()

大きい場合content:

  • [0000ms] response.write(content)//最初の MTU が送信されます
  • [0001ms]2番目のMTUが送信されます
  • [0070ms]クライアントからACKパッケージを受信しました
  • [0071ms]response.end()

考えられる説明:

ヘッダーが設定されていない場合Content-Length、データは「チャンク」モードで転送されます。「チャンク」モードでは、サーバーもクライアントもデータの正確な長さを認識していないため、クライアントは次のパッケージがあるかどうかを確認するためにしばらく (200 ミリ秒) 待機します。

ただし、この説明は別の疑問を提起します。より大きなケースで、なぜ content クライアントは 200 ミリ秒も待機しなかったのですか (代わりに、約 50 ミリ秒しか待機しませんでした)。

于 2013-06-06T09:02:54.683 に答える