2

私が書いている HTTP サーバーを高負荷時に適切に動作させようとしていますが、よく理解できない奇妙な動作が発生しています。

私のテストでは、サーバー プロセスを追跡しながらab、ループバック インターフェース上で 1000 の同時実行レベル ( ) で (Apache ベンチマーク プログラム) を使用します。ab -n 50000 -c 1000 http://localhost:8080/apaStrace は、問題がすぐに再現できるように処理を十分に遅くし、完了後にサーバーの内部をある程度デバッグできるようにします。tcpdumpまた、テストの実行中にネットワーク トラフィックをキャプチャします。

何が起こるかというとab、テストの実行中にしばらく停止し、接続が返されたと不平を言うことECONNRESETです。これは少し奇妙に感じます。サーバーにはすべてを処理するための帯域幅がない可能性があるため、接続のタイムアウトを簡単に受け入れることができますが、それは合理的に戻るべきではないETIMEDOUTか、またはECONNREFUSEDすべての接続を受け入れることができない場合でも?

Wireshark を使用して、返される最初の接続を構成するパケットを抽出しましたECONNRESET。その簡単なパケット リストは次のように なります。 (この接続のファイルパケットリスト 全体は、ここで入手できます。)tcpdump

このダンプからわかるように、(SYN数回の再送信の後) 接続が受け入れられ、その後、要求が数回再送信され、サーバーが接続をリセットします。私は疑問に思っています、これが起こる原因は何ですか?通常、Linux の TCP 実装は、TCP ウィンドウにスペースがある限り、読み取りプロセスが受信を選択する前にデータに ACK を送信します。不足しているある種の共有バッファはありますか? 最も重要なことは、カーネルRSTが単に待機してクライアントにさらに再送信させるのではなく、突然パケットで応答するのはなぜですか?

記録として、プロセスの strace は、この接続のポート (ポート 56946) からの接続を受け入れることさえないことを示しているため、これは Linux が独自に行うことのようです。ab の同時実行レベルが十分に低い限り、サーバーは完全に正常に動作し (約 100 までは完全に正常に動作し、その後 100 から 500 の間のどこかで断続的に失敗し始めます)、その要求スループットがかなり一定であることも注目に値します。同時実行レベルに関係なく (トレースされていない限り、1 秒あたり 6000 ~ 7000 のリクエストを処理します)。問題が発生する頻度とバックログの設定との間に特定の相関関係は見つかりませんでしたlisten()(現在は 128 を使用していますが、1024 まで試してみましたが、違いはないようです)。

念のために言うと、私はこの AMD64 ボックスで Linux 3.2.0 を実行しています。

4

1 に答える 1

0
  1. バックログ キューがいっぱいになりました。したがって、SYN再送信します。

  2. その後、スロットが利用可能になりましたSYN/ACK

  3. その後、GET が送信され、その後 4 回の再送信が行われましたが、これについては説明できません。

  4. その後、サーバーは接続をあきらめてリセットしました。

サーバーに同時実行性またはスループットの問題があり、接続を十分に迅速に受け入れることができないと思われます。accept() を呼び出し、受け入れられたソケットを処理するために別のスレッドを開始するか、それを処理するジョブをスレッド プールにキューイングする以外に何もしない専用のスレッドが必要です。次に、バックログ キューにあり、I/O 再試行を受信して​​いる接続で Linux が接続をリセットすると推測しますが、それは推測に過ぎません。

于 2012-12-31T05:59:30.797 に答える