ロードテスト:1秒あたりのリクエストを生成する方法


14

Zeroc-ICEで実行されるサーバーコンポーネントがあります。ロードテストをしたいとき、並列ライブラリを使用して複数の要求を作成すると思いました。しかし、それはそのようになってしまいます。C#のParallel(Parallel.For)ライブラリを使用する方が簡単なようですが、すべてを同じ瞬間に正確に生成しているようには見えません。したがって、1秒あたりN個の要求を作成するための定義にはなりません。どうすればいいですか?最初に負荷テストをしたい人はだれでも実際にこれについて考えると思います。

  1. 実際に1秒あたりN個のリクエストを実際に作成する効率的な方法は何ですか?

  2. もう1つの神話は、並列プログラミングに関するものです。一般的にC#または.Netで並列プログラミングパターンを使用している場合は、ご理解ください。5つのプロセスがあるとします。5つのプロセスすべてを同時に開始する方法。リソースを消費することはどういう意味ですか?私はネット上で入手可能な多くの資料を読んでみましたが、質問に対する答えよりも多くの質問があります。

  3. Parallel.Forを使用して、N個のスレッドを作成し、時間を測定しました。次に、タスクの列挙にTask.Factory.startを使用して同じことを試みました。測定された時間は異なっていました。それで、これらを使用することの正確な違いは何ですか?対応するクラスをいつ使用し、どのような目的のために正確に使用する必要がありますか?私たちは多くの富を持っていることが多いのですが、それをどうやって区別するのか正確にはわかりません。これは私にとってそのようなケースの1つであり、なぜ別のものを使用すべきではないのかを見つけることができません。

  4. 私はストップウォッチクラスを使用して、これらの時間を測定しました。私のシナリオでは、コンポーネントの負荷テストで、応答時間を測定する方法は何でしょうか。ストップウォッチは私にとって最良の解決策のようです。ご意見をお待ちしています。

ps:Webアプリケーション用の負荷テストツールは多数あります。私のものは、サーバーコンポーネントのカスタマイズされたケースです。私の質問は、1秒あたりN個のスレッドの作成に関するものです。

すべての意見を歓迎します。プログラミングの問題ではないと考えないでください。もちろんです。自分で製品の品質を知りたいプログラマーが自分で製品のパフォーマンスを知りたい場合は、ベルを鳴らさなければなりません。


よくある質問は、それが特定のプログラミングの問題に関係するかどうか、そしてそれがプログラミングの専門家における実際的な回答可能な問題かどうかを尋ねることができるということです。懐疑的でこれにフラグを立てている人々。コメントしてください。
キング

「同じ瞬間」とはどういう意味ですか?TPLまたはPLinqを強制するために、何らかの方法でそれを達成できるかどうか疑問に思います。
ゲルトアーノルド

私の質問は、毎秒N個のリクエストを生成することです。したがって、このシナリオの同じ瞬間は、並列の使用がスレッドを並列に開始するという私の理解に向けられていました。
キング

逐次分析を行ったことがありますか?

3
プログラミングに関係しているかもしれませんが、投稿にはあまりにも多くの質問があります(少なくとも4つ)。質問が広すぎるため、終了する前に質問したい1つの質問に減らします。ちょうどあなたが言及した10000、テストマシンのコアの数などの関連情報を提供します)。通常、コードを表示すると役立ちます。
ゲルトアーノルド

回答:


10

すべての答えがありません。うまくいけば、私はそれにいくつかの光を当てることができます。

.NETのスレッドモデルに関する以前のステートメントを簡素化するには、Parallel LibraryがTasksを使用し、Tasksの既定のTaskSchedulerがThreadPoolを使用することを知ってください。階層を上に行くほど(ThreadPoolが一番下になります)、アイテムを作成する際のオーバーヘッドが大きくなります。余分なオーバーヘッドは確かに遅くなるという意味ではありませんが、そこにあることを知っておくと良いでしょう。最終的に、マルチスレッド環境でのアルゴリズムのパフォーマンスは、その設計次第です。連続してうまく機能するものは、並行して同様に機能しない場合があります。複雑で速いルールを与えるにはあまりにも多くの要因が関係しているため、あなたがしようとしていることに応じて変化します。ネットワークリクエストを処理しているので、簡単な例を示します。

私はソケットの専門家ではなく、Zeroc-Iceについてほとんど何も知らないことを述べさせてください。私は非同期操作について少し知っていますが、これは本当に役立つでしょう。ソケットを介して同期要求を送信する場合、を呼び出すとSocket.Receive()、要求を受信するまでスレッドがブロックされます。これは良くありません。スレッドはブロックされているため、これ以上リクエストを行うことはできません。Socket.Beginxxxxxx()を使用して、I / O要求が行われ、ソケットのIRPキューに入れられ、スレッドは続行されます。つまり、スレッドは実際には何もブロックせずにループで何千ものリクエストを行うことができます!

私が正しく理解している場合、テストコードでZeroc-Iceを介した呼び出しを使用しており、実際にはHTTPエンドポイントに到達しようとはしていません。その場合、Zeroc-Iceの仕組みがわからないことは認められます。ただし、ここリストされているアドバイス、特にパートに従うことをお勧めしますConsider Asynchronous Method Invocation (AMI)。ページにこれが表示されます。

AMIを使用することにより、クライアントは呼び出しが送信されるとすぐに(または、すぐに送信できない場合はキューに入れられて)制御のスレッドを取り戻し、クライアントはそのスレッドを使用してその間に他の有用な作業を実行できます。

これは、上記で.NETソケットを使用して説明したものと同等のようです。多くの送信を行う際にパフォーマンスを向上させる方法は他にもありますが、ここから始めるか、そのページにリストされている他の提案から始めます。あなたはあなたのアプリケーションの設計について非常に曖昧だったので、私は上記よりも具体的にすることができます。覚えておいて、必要なことを行うために絶対に必要なスレッドより多くのスレッドを使用しないでください。

擬似コードのいくつかの例(実際に学習する必要なく、できるだけ氷に近づけようとしました):

var iterations = 100000;
for (int i = 0; i < iterations; i++)
{
    // The thread blocks here waiting for the response.
    // That slows down your loop and you're just wasting
    // CPU cycles that could instead be sending/receiving more objects
    MyObjectPrx obj = iceComm.stringToProxy("whateverissupposedtogohere");
    obj.DoStuff();
}

より良い方法:

public interface MyObjectPrx : Ice.ObjectPrx
{
    Ice.AsyncResult GetObject(int obj, Ice.AsyncCallback cb, object cookie);
    // other functions
}

public static void Finished(Ice.AsyncResult result)
{
    MyObjectPrx obj = (MyObjectPrx)result.GetProxy();
    obj.DoStuff();
}

static void Main(string[] args)
{
    // threaded code...
    var iterations = 100000;
    for (int i = 0; i < iterations; i++)
    {
        int num = //whatever
        MyObjectPrx prx = //whatever
        Ice.AsyncCallback cb = new Ice.AsyncCallback(Finished);
        // This function immediately gets called, and the loop continues
        // it doesn't wait for a response, it just continually sends out socket
        // requests as fast as your CPU can handle them.  The response from the
        // server will be handled in the callback function when the request
        // completes.  Hopefully you can see how this is much faster when 
        // sending sockets.  If your server does not use an Async model 
        // like this, however, it's quite possible that your server won't 
        // be able to handle the requests
        prx.GetObject(num, cb, null);
    }
}

スレッドをより多く!=ソケットを送信しようとするとき(または実際に何かをするとき)のパフォーマンスが向上することに注意してください。スレッドは、作業中の問題を自動的に解決するという点で魔法ではありません。理想的には、スレッドが待機に多くの時間を費やしていない限り、コアごとに1つのスレッドが必要です。コンテキスト切り替えが発生し、リソースが浪費されるため、各要求を独自のスレッドで実行するのは悪い考えです。(それについて私が書いたものをすべて見たい場合は、編集をクリックして、この投稿の過去の改訂版を見てください。手元の主な問題を曇らせているように見えたので削除しました。)

1秒間に大量のリクエストを行う場合は、スレッドでこれらのリクエストを確実に行うことができます。ただし、スレッドの作成で行き過ぎないでください。バランスを見つけて、それにこだわる。非同期モデルと同期モデルを使用すると、パフォーマンスが向上します。

それがお役に立てば幸いです。


なぜパフォーマンスについてそんなに話しているのですか?それはOPが望んでいるものではないようです。
svick

@svickのopsの元の投稿には元々4つの質問がありましたが、彼らは並列対タスクのパフォーマンスについて質問し、それを編集してから再び入力しました。最終的に、彼の質問はパフォーマンスに関係していますが、彼は一般的な考え方は正しいのですが、実装には明らかに欠けています。私が最後に指摘した答えは、彼編集しなかった質問に答えると思います。
クリストファーカレンズ

彼らは閉会するために投票したかったので、私は私の質問を減らすことを余儀なくされました。今では、それらを持っていることはここで有効です。@ChristopherCurrensは、タスクへのスレッドプールとの違いに対して+1の良い点です。それは私の理解を広げました。しかし、1秒あたりN個のリクエストを生成する方法が実際にどのように可能であるのか、いまだに立ち往生しています。それを行う最良の方法は何ですか?
キング

@King-私は思っていたほど明確ではなかったと思います。最後の3〜4段落が役立つと思いました。私はあなたが既にある種のループをすでに使用していると仮定していました。それを行っていた場合、問題はソケットの送受信がブロックされているため、リクエストが遅くなることです。たぶん、疑似コードの例を投稿する時間を見つけるでしょう。
クリストファーカレンズ

実際にICEで送信しても問題ありません。問題は、実際にN個の要求を作成する実装と、その数Nに当てはまる何かを定義するものです。
キング

2

質問1)をスキップして、#2に進みます。これは、一般に、目的を達成するために受け入れられる方法だからです。以前は、1秒あたりnメッセージを達成するために、p AppDomainsを起動する単一のプロセスを作成できました。基本的に、各AppDomainは、特定の時点に到達すると(タイマーを使用して)要求ループの実行を開始します。この時間は、AppDomainごとに同じにして、サーバーが同じ時点でヒットするようにします。

このような何かがあなたのリクエストを送信するために動作するはずです:

WaitCallback del = state => 
{ 
    ManualResetEvent[] resetEvents = new ManualResetEvent[10000]; 
    WebClient[] clients = new WebClient[10000]; 

    for (int index = 0; index < 10000; index++) 
    { 
        resetEvents[index] = new ManualResetEvent(false); 
        clients[index] = new WebClient(); 

        clients[index].OpenReadCompleted += new OpenReadCompletedEventHandler (client_OpenReadCompleted); 

        clients[index].OpenReadAsync(new Uri(@"<REQUESTURL>"), resetEvents[index]); 
    } 

    bool succeeded = ManualResetEvent.WaitAll(resetEvents, 10000); 
    Complete(succeeded); 

    for (int index = 0; index < 10000; index++) 
    { 
        resetEvents[index].Dispose(); 
        clients[index].Dispose(); 
    } 
}; 

while(running)
{
    ThreadPool.QueueUserWorkItem(del);
    Thread.Sleep(1000);
}

これにより、実行しているマシンのパフォーマンスが低下する可能性が高いため、リソースがある場合(アプリドメインの代わりにプロセスを使用して)、複数の異なるマシンから同様のタイプのループを常に実装できます。

3番目の質問については、このリンクにhttp://www.albahari.com/threading/を読んでください。

最後に、ストップウォッチとヒットカウンターを組み合わせて、サーバー上の継続時間と一意のヒットの両方を追跡する必要があります。これにより、事後に分析を行うことができます。


2
ここで個別のAppDomainを作成する必要がある理由は何ですか?それは完全に不要なようです。
svick

0

Nが適度に小さい場合は、スレッドを気にしないでください。1秒あたりN個のリクエストを生成するには、ウォールクロック時間(DateTime.Now)を使用します。リクエストの前後に時間をかけてSleepから、次のリクエストを遅らせるためにa を追加します。

たとえば、N = 5(200 ms)の場合:

Before request: 12:33:05.014
After request: 12:33:05.077
Sleep(137)
Before request: 12:33:05.214
After request: 12:33:05.271
Sleep(131)

これは完璧ではありません。Sleep正確ではない場合があります。偏差の実行カウントを保持し(X番目の要求の前に、時間はX-1 / Nになるはずです)、それに応じてスリープ期間を調整できます。

Nが大きくなりすぎたら、Mスレッドを作成し、各スレッドが同じ方法でN / Mリクエストを生成するようにします。


非常に多くのリクエストを生成する必要があります。そのため、100スレッド前でもメモリ(4GB RAM)を消費するため、これはオプションにはなりません。
キング

250Kのコ​​ードで、1つのスレッドから毎秒20.000のリクエストを作成しました。とにかく100スレッドを実行するのに十分なCPUがありません(そのクラスのマシンには4GBが付属していません)。次の問題は、これらすべての要求を押し出すことです。負荷作成者とサーバーの間に10ギガビット/秒のイーサネットがありますか?そのため、実際の要件を確認することをお勧めします。
MSalters

明確にするために、私は20+ Gbpsのようなものを持っています。だからそれは問題ではありません。機械のクラスについて、あなたは何に言及しますか?プロセッサーの数?
キング

@King:100スレッドをプッシュするには、48コアのマシンが必要です。たとえば、SGIはその数のコアを備えたマシンを販売していますが、通常は32 GB以上のコアを搭載しています。
MSalters

0

.NETプロジェクトの負荷テストを達成する最も簡単な方法は、Visual StudioのUltimateエディションを購入することです。これには、負荷テストを含むあらゆる種類のテストを実行するのに役立つ統合テストツールが付属しています。負荷テストは、1台のPCで仮想ユーザーを作成するか、多数のユーザーに複数の仮想ユーザーを作成することで実行できます。また、テスト中に追加データを返すためにターゲットサーバーにインストールできる小さなプログラムもあります。

しかし、これは高価ですが、究極のエディションには多くの機能が付属しているため、すべてを使用すると、よりリーズナブルな価格になります。


0

Xスレッドのすべてがリソースにまったく同時にヒットするようにしたい場合は、各スレッドをカウントダウンラッチの背後に置き、セマフォチェック間の短い待機期間を指定できます。

C#には実装があります(http://msdn.microsoft.com/en-us/library/system.threading.countdownevent(VS.100).aspx)。

同時に、システムのストレステストを行っている場合は、実際に競合状態も確認する必要があります。この場合、ランダム化された周波数とピーク/ファールで時間とともに変動する各スレッドにスレッドスリープ期間を設定します。

同様に、実際に複数のリクエストを迅速に送信したくない場合があります。サーバーを悪い状態にしたり、メッセージの消費と送信に多くの時間を費やす少数のスレッドをセットアップすることで、実際のパフォーマンスをテストすることに成功する可能性があります遅い進行中のメッセージを処理するためにサーバーが独自のスレッドをスピンアップする必要がある可能性が高いため、ソケットを介してやり取りします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.