サーバーへの同時TCP接続を100回行うC#NUnitテストを作成しています。テストの目的は、サーバーにストレスをかけることです。
これを行うために、テストは100個の新しいスレッドを作成し、それらをループして呼び出しthread.Start()
、次にそれらを再度ループしてを呼び出しますthread.Join()
。
各スレッドは、TCP接続を確立し、いくつかのデータを要求し、受信したデータがnullでないかどうかを確認してから、完了までにかかった時間を出力するメソッドを実行します。
私が気付いたのは、100の接続では、後でコンソールに書き込むスレッドの場合、各スレッドがタスクを完了するのに必要な時間が2秒から50秒に増加することです。ただし、への各呼び出しの間に2秒の遅延を導入するとthread.Start()
、必要な時間はスレッドごとに2秒になります。
遅延なしのシナリオでは、必要な時間の増加は、単体テストを実行しているマシン(つまり、開発ボックス)の問題が原因である可能性があるのではないかと思います。たとえば、.NET / Windows 7では、リソースが原因で100個のTCP接続を次々に作成できない可能性があります。
TCPプログラミングの知識を持っている人がコメントしてくれませんか?開発ボックスがボトルネックであるかどうかを判断するために使用できるツールは何ですか?
目標は、結果がサーバーの実際に有効なストレステスト結果であるかどうかを知ることです。
public void ServerStressTest()
{
const int NUMBER_OF_REQUESTS = 10;
const int DELAY_BETWEEN_REQUESTS = 0;
var threads = new System.Collections.Generic.List<Thread>();
var urls = new StaticDataUrls();
Console.WriteLine(string.Format("Requesting static data from the server {0} times with {1} seconds delay between subsequent requests...", NUMBER_OF_REQUESTS, DELAY_BETWEEN_REQUESTS));
for (int i = 0; i < NUMBER_OF_REQUESTS; i++)
{
var callNumber = i; // prevent access to modified closure
threads.Add(new Thread(() => FetchStaticData(urls, callNumber)));
}
threads.Apply(t =>
{
Thread.Sleep(DELAY_BETWEEN_REQUESTS * 1000);
t.Start();
});
threads.Apply(t => t.Join());
}
private void FetchStaticData(StaticDataUrls urls, int callNumber)
{
var restAdapter = new RestAdapter(true, new Log4NetLogger(GetType()));
var stopwatch = Stopwatch.StartNew();
var underlyingResults = restAdapter.Get(urls.UnderlyingUrl);
var clientResults = restAdapter.Get(urls.ClientUrl);
stopwatch.Stop();
var missingData = new System.Collections.Generic.List<string>();
if(string.IsNullOrEmpty(clientResults.ResponseData)) missingData.Add("client");
if(string.IsNullOrEmpty(underlyingResults.ResponseData)) missingData.Add("underlying");
Console.WriteLine(missingData.Count > 0
? string.Format("Call {0}: No {1} data received in {2} seconds", callNumber, string.Join(", ", missingData.ToArray()), stopwatch.Elapsed.Seconds)
: string.Format("Call {0}: Completed with all data in {1} seconds", callNumber, stopwatch.Elapsed.Seconds));
}