ck.
ck.

Reputation: 1056

Making multiple TCP connections from a single box for stress testing

I'm writing a C# NUnit test that makes 100 simultaneous TCP connections to a server. The purpose of the test is to stress the server.

To do this, the test creates 100 new threads, loops over them and calls thread.Start(), then loops over them again and calls thread.Join().

Each thread will execute a method that makes the TCP connection, requests some data, checks if the received data is not null, then prints how long it took to complete.

What I've noticed is that with 100 connections, the time required for each thread to complete its task rises from 2 seconds to 50 seconds, for threads that write to the console later. However, when I introduce a 2 second delay between each call to thread.Start(), the time required is 2 seconds for every single thread.

W.r.t. the no-delay scenario, I'm wondering if the increase in time required could be due to issues on the machine running the unit test (i.e. my dev box). For example, perhaps .NET/Windows 7 doesn't allow 100 TCP connections to be created one after another due to resourcing.

Could someone with knowledge on TCP programming comment please? What tools can I use to determine if my dev box is the bottle neck?

The goal is to know if the results are actually valid stress testing results for the server.

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));
}

Upvotes: 1

Views: 1453

Answers (1)

Chimera
Chimera

Reputation: 6018

What is likely happening is that when you have no delay between starting the new threads, your CPU/network load goes up and each thread takes longer as each thread is sharing CPU time with the other threads.

However, when you start each thread 2 seconds apart you are essentially allowing each to complete before a new thread begins.

I would be surprised if the .NET runtime didn't give some type of exception if you tried to open too many TCP connections.

The no delay method is a decent stress test.

Upvotes: 1

Related Questions