Создание нескольких соединений TCP из одного ящика для стресс-тестирования
Я пишу тест C# NUnit, который делает 100 одновременных TCP-соединений с сервером. Цель теста - нагрузка на сервер.
Для этого тест создает 100 новых потоков, зацикливает их и вызывает thread.Start()
затем снова зацикливается на них и вызывает thread.Join()
,
Каждый поток выполнит метод, который устанавливает TCP-соединение, запрашивает некоторые данные, проверяет, не являются ли полученные данные ненулевыми, а затем печатает, сколько времени потребовалось для завершения.
Что я заметил, так это то, что при 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));
}
1 ответ
Вероятно, происходит то, что когда у вас нет задержки между запуском новых потоков, нагрузка на ваш ЦП / сеть возрастает, и каждый поток занимает больше времени, так как каждый поток делит время ЦП с другими потоками.
Однако, когда вы запускаете каждый поток с интервалом в 2 секунды, вы, по сути, позволяете завершить каждый поток до начала нового потока.
Я был бы удивлен, если бы среда выполнения.NET не давала какого-то исключения, если вы пытались открыть слишком много TCP-соединений.
Метод без задержек - достойный стресс-тест.