17

複数のスレッドにまたがるリクエストをヒットして、Web サイトのパフォーマンスをテストしようとしています。各スレッドはn回実行されます。(for ループ内)

しかし、私は問題に直面しています。具体的には、内部例外を伴う WebException (「リモート サーバーに接続できません」):

システムに十分なバッファ領域がないか、キューがいっぱいだったため、ソケットに対する操作を実行できませんでした 127.0.0.1:52395

スレッドあたり 500 回の反復で 100 スレッドを実行しようとしています。

最初はHttpWebRequestSystem.Net で使用して、サーバーへの GET 要求を作成していました。現在WebClient、各反復が新しいソケットを使用していると想定して使用しています(したがって、短期間で100 * 500ソケット)。WebClient (スレッドごとに 1 回インスタンス化される) は 1 つのソケットしか使用しないと想定しました。

一度に 50,000 個のソケットを開く必要はありません。GET 要求を送信し、応答を受信し、ソケットを閉じて、次のループ反復で使用できるように解放したいからです。問題になることは理解しています

ただし、WebClient を使用しても、多数のソケットが要求されており、その結果、多数のソケットがTIME_WAITモードになっています (netstat を使用して確認)。これにより、他のアプリケーション (インターネット ブラウザーなど) がハングし、機能が停止します。

ソケットが最終的にこの TIME_WAIT 状態を終了するように見えるため、反復回数やスレッド数を減らしてテストを実行できます。ただし、Web サーバーの機能を十分にテストしていないため、これは解決策ではありません。

質問:

TIME_WAIT 状態とソケットの枯渇を防ぐために、各スレッドの反復後に (クライアント側から) 明示的にソケットを閉じるにはどうすればよいですか?

コード:

HttpRequest をラップするクラス

編集: WebClient を using でラップしたため、反復ごとに新しいインスタンスがインスタンス化され、使用され、破棄されます。問題はまだ解決していません。

  public sealed class HttpGetTest : ITest {
    private readonly string m_url;

    public HttpGetTest( string url ) {          
        m_url = url;
    }

    void ITest.Execute() {
        using (WebClient webClient = new WebClient()){
            using( Stream stream = webClient.OpenRead( m_url ) ) {          
            }
        }
    }
}

新しいスレッドを作成する ThreadWrapperClass の部分:

public void Execute() {
    Action Hammer = () => {
        for( int i = 1; i <= m_iterations; i++ ) {
            //Where m_test is an ITest injected through constructor
            m_test.Execute();
        }       
    };
    ThreadStart work = delegate {
        Hammer();
    };
    Thread thread = new Thread( work );
    thread.Start();
}
4

5 に答える 5

14

TIME_WAITの目的を理解していますか?これは、前のトランザクションから失われたパケット(正常に再送信された)がその期間内にまだ配信されていない可能性があるため、ポートを再利用することが安全でない期間です。

レジストリのどこかで微調整することもできますが、これが賢明な次のステップであるかどうかは疑問です。

テスト環境で現実的な負荷を作成した私の経験は、非常に苛立たしいものでした。確かに、ローカルホストからロードテスターを実行することは決して現実的ではありません。.nethttpapisを使用して行ったほとんどのネットワークテストでは、サーバー自体よりもクライアントでより多くのうなり声が必要なようです。

そのため、サーバーに負荷をかけるために2台目のマシンに移動することをお勧めします...ただし、国内のルーティング機器が、適切に作成されたサーバーに何らかの負荷をかける可能性のある接続数に近い場所をサポートすることはめったにありません。アプリなので、ルーティング/スイッチング機器もアップグレードする必要があります!

最後に、.netHttpクライアントAPIの周りにいくつかの本当に奇妙で予期しないパフォーマンスの問題がありました。一日の終わりに、彼らはすべてHttpWebRequestを使用して手間のかかる作業を行います。IMOは、パフォーマンスがそれほど高くありません。DNSは同期しており、APIを非同期で呼び出す場合でも(単一のホストからのみ要求している場合は問題ありません)、継続的に使用した後、クライアントがIO制約ではなくCPU制約になるまでCPU使用率が上昇します。持続的で重い負荷を生成しようとしている場合、HttpWebRequestに依存するリクエストの多いアプリはIMOに偽の投資です。

全体として、かなりトリッキーな仕事であり、最終的には、より良い機器の艦隊に費やすための十分な現金を持っていない限り、野生でしか証明できないものです。

[ヒント:非同期ソケットAPIとサードパーティのDNSクライアントライブラリを使用して作成された自分のクライアントから、はるかに優れたパフォーマンスが得られました]

于 2012-07-19T21:48:01.727 に答える
3

Q: TIME_WAIT 状態を防ぐために、ソケットを明示的に閉じるにはどうすればよいですか?

A: ねえ、TIME_WAIT は不可欠であり、重要です! - TCP/IP 自体の一部です!

OS を調整して TIME_WAIT を減らすことができます (これは悪影響を与える可能性があります)

また、OS を調整して #/ephemeral ポートを増やすことができます。

TIME_WAIT が存在する理由と、それが良いことである理由に関するリンクは次のとおりです。

于 2012-07-19T22:15:27.237 に答える
2

アプリでソケットを閉じたり、リソースを解放したりする問題ではありません。TIME _WAIT は、解放されたソケットの TCP スタック timeot であり、そのソケットへの以前の接続から「残った」パケットが期限切れになることが事実上不可能になるまで、ソケットの再使用を防ぎます。

テスト目的で、待機時間をデフォルト (数分、AFAIK) からより小さい値に減らすことができます。サーバーの負荷テストを行うときは、6 秒に設定しました。

レジストリのどこかにあります。Google で検索すると見つかります。

それを見つけた:

TIME_WAIT 遅延の変更

于 2012-07-19T21:33:30.150 に答える
1

WebClient が割り当てたリソースを強制的に削除していないようです。返されたストリームで Using を実行していますが、WebClient にはまだリソースがあります。

WebClient のインスタンス化を using ブロックでラップするか、URL からの読み取りが完了したら手動で dispose を呼び出します。

これを試して:

public sealed class HttpGetTest : ITest {
    private readonly string m_url;

    public HttpGetTest( string url ) {
        m_url = url;        
    }

    public void ITest.Execute() {
        using( var m_webClient = new WebClient())
        {
            using( Stream stream = m_webClient.OpenRead( m_url ) ) 
            {

            }
        }
    }
}
于 2012-07-19T21:29:27.063 に答える