40

「ab」を使用して Web サーバーのベンチマークを実行すると、大量のリクエストを送信した後、しばらくの間フリーズし、20 秒ほど後に続行します。

Ruby で記述された次の HTTP サーバー シミュレーターを考えてみましょう。

require 'socket'

RESPONSE = "HTTP/1.1 200 OK\r\n" +
           "Connection: close\r\n" +
           "\r\n" +
           "\r\n"

buffer = ""
server = TCPServer.new("127.0.0.1", 3000)  # Create TCP server at port 3000.
server.listen(1024)                        # Set backlog to 1024.
while true
    client = server.accept             # Accept new client.
    client.write(RESPONSE)             # Write a stock "HTTP" response.
    client.close_write                 # Shutdown write part of the socket.
    client.read(nil, buffer)           # Read all data from the socket.  
    client.close                       # Close it.
end

次に、次のように ab を実行します。

ab -n 45000 -c 10 http://127.0.0.1:3000/

最初の数秒間、ab は想定どおりにジョブを実行し、CPU を 100% 使用します。

Benchmarking 127.0.0.1 (be patient)
Completed 4500 requests
Completed 9000 requests
Completed 13500 requests

約 13500 のリクエストの後、システムの CPU 使用率は 0% に低下します。ab は何かに固まっているようです。この時点で、サーバーは accept() を呼び出しているため、問題はサーバーにはありません。約 20 秒後、ab は何も起こらなかったかのように続行し、再び 100% の CPU を使用しますが、数秒後に再びフリーズするだけです。

カーネル内の何かが接続を調整していると思われますが、何が原因でしょうか? OS X Leopard を使用しています。Linux でも同様の動作が見られましたが、フリーズははるかに多くのリクエストで発生し、それほど頻繁には発生しません。

この問題により、大規模な HTTP ベンチマークを実行できません。

4

3 に答える 3

55

エフェメラル ポートが不足しているようです。確認するには、netstatコマンドを使用して、状態で数千のポートを探しますTIME_WAIT

Mac OS X では、デフォルトの一時ポート範囲は 49152 から 65535 で、合計 16384 ポートです。sysctlこれは、次のコマンドで確認できます。

$ sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last
net.inet.ip.portrange.first: 49152
net.inet.ip.portrange.last: 65535

エフェメラル ポートを使い果たすと、通常、TIME_WAIT状態が期限切れになるまで (2 * 最大セグメント ライフタイム)、特定のポート番号を再利用できるようになるまで待つ必要があります。Linux および Solaris のデフォルトである 32768 から開始するように範囲を変更することで、ポートの数を 2 倍にすることができます。(最大ポート番号は 65535 であるため、ハイエンドを増やすことはできません。)

$ sudo sysctl -w net.inet.ip.portrange.first=32768
net.inet.ip.portrange.first: 49152 -> 32768

IANA によって指定された公式の範囲は 49152 から 65535 であり、一部のファイアウォールは、動的に割り当てられたポートがその範囲内にあると想定する場合があることに注意してください。ローカル ネットワークの外でより広い範囲を使用するには、ファイアウォールを再構成する必要がある場合があります。

状態の期間を制御する最大セグメント ライフタイム ( sysctl net.inet.tcp.mslMac OS X の場合)を減らすこともできTIME_WAITますが、古い接続が同じポート番号を使用している新しい接続と混同される可能性があるため、これは危険です。オプションで特定のポートにバインドしたり、SO_REUSEADDRオプションで閉じたりするトリックもありSO_LINGERますが、それらも古い接続と新しい接続が混同される可能性があるため、一般的に悪い考えと見なされます。

于 2009-08-01T17:42:09.717 に答える
26

TIME_WAITポート数を増やす代わりに、Mac OS Xで の長さを変更します。

これは開発中のみ機能しますが、abタイムアウトすることなく、必要な数のリクエストを要求できるようになりました。

次のように、デフォルトのタイムアウトを 1000 ミリ秒に設定します。

$ sudo sysctl -w net.inet.tcp.msl=1000
net.inet.tcp.msl: 15000 -> 1000

他の回答で言及されている brianp.net ページは利用できなくなりました。インターネット アーカイブから取得できます。

于 2011-07-14T19:51:09.060 に答える