Web Services c#如何对Web服务进行负载测试

vngu2lb8  于 2022-11-15  发布在  C#
关注(0)|答案(4)|浏览(194)

我需要测试我们的应用程序中是否有内存泄漏,并监视在处理请求时内存使用量是否增加太多。我正在尝试开发一些代码来对我们的api/webservice方法进行多个同时调用。此api方法不是异步的,需要一些时间来完成其操作。
我做了很多关于任务、线程和并行性的研究,但到目前为止我还没有什么运气。问题是,即使尝试了下面所有的解决方案,结果总是一样的,似乎一次只处理了两个请求。
已尝试:

  • 〉在一个简单的for循环中创建任务,并使用TaskCreationOptions设置或不设置任务来启动它们。LongRunning
  • 〉在一个简单的for循环中创建线程,并以高优先级或非高优先级启动它们
  • 〉在一个简单的for循环中创建一个操作列表,并使用
Parallel.Foreach(list, options, item => item.Invoke)
  • 〉直接在Parallel.For循环中运行(如下所示)
  • 〉使用和不使用Options和TaskScheduler运行TPL方法
  • 〉已尝试使用不同的MaxParallelism和最大线程数值
  • 〉也检查了this post,但也没有帮助。(我可能遗漏了什么吗?)
  • 〉查看了Stackoverflow中的一些其他帖子,但是对于F#解决方案,我不知道如何正确地将它们翻译成C#。(我从未使用过F#...)
    (Task调度程序类取自msdn
    这是我的基本结构:
public class Test
{
    Data _data;
    String _url;

    public Test(Data data, string url)
    {
        _data = data;
        _url = url;
    }

    public ReturnData Execute()
    {
         ReturnData returnData;

         using(var ws = new WebService())
         {
              ws.Url = _url;
              ws.Timeout = 600000;

              var wsReturn = ws.LongRunningMethod(data);

              // Basically convert wsReturn to my method return, with some logic if/else etc
         }
         return returnData;
    }
}

sealed class ThreadTaskScheduler : TaskScheduler, IDisposable
    {
        // The runtime decides how many tasks to create for the given set of iterations, loop options, and scheduler's max concurrency level.
        // Tasks will be queued in this collection
        private BlockingCollection<Task> _tasks = new BlockingCollection<Task>();

        // Maintain an array of threads. (Feel free to bump up _n.)
        private readonly int _n = 100;
        private Thread[] _threads;

        public TwoThreadTaskScheduler()
        {
            _threads = new Thread[_n];

            // Create unstarted threads based on the same inline delegate
            for (int i = 0; i < _n; i++)
            {
                _threads[i] = new Thread(() =>
                {
                    // The following loop blocks until items become available in the blocking collection.
                    // Then one thread is unblocked to consume that item.
                    foreach (var task in _tasks.GetConsumingEnumerable())
                    {
                        TryExecuteTask(task);
                    }
                });

                // Start each thread
                _threads[i].IsBackground = true;
                _threads[i].Start();
            }
        }

        // This method is invoked by the runtime to schedule a task
        protected override void QueueTask(Task task)
        {
            _tasks.Add(task);
        }

        // The runtime will probe if a task can be executed in the current thread.
        // By returning false, we direct all tasks to be queued up.
        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            return false;
        }

        public override int MaximumConcurrencyLevel { get { return _n; } }

        protected override IEnumerable<Task> GetScheduledTasks()
        {
            return _tasks.ToArray();
        }

        // Dispose is not thread-safe with other members.
        // It may only be used when no more tasks will be queued
        // to the scheduler.  This implementation will block
        // until all previously queued tasks have completed.
        public void Dispose()
        {
            if (_threads != null)
            {
                _tasks.CompleteAdding();

                for (int i = 0; i < _n; i++)
                {
                    _threads[i].Join();
                    _threads[i] = null;
                }
                _threads = null;
                _tasks.Dispose();
                _tasks = null;
            }
        }
   }

以及测试代码本身:

private void button2_Click(object sender, EventArgs e)
    {
        var maximum = 100;
        var options = new ParallelOptions
        {
             MaxDegreeOfParallelism = 100,
             TaskScheduler = new ThreadTaskScheduler()
        };

        // To prevent UI blocking
        Task.Factory.StartNew(() =>
        {
            Parallel.For(0, maximum, options, i =>
            {
                var data = new Data();
                // Fill data
                var test = new Test(data, _url); //_url is pre-defined
                var ret = test.Execute();

               // Check return and display on screen
               var now = DateTime.Now.ToString("HH:mm:ss");
               var newText = $"{Environment.NewLine}[{now}] - {ret.ReturnId}) {ret.ReturnDescription}";

               AppendTextBox(newText, ref resultTextBox);
           }
     }

    public void AppendTextBox(string value, ref TextBox textBox)
    {
        if (InvokeRequired)
        {
            this.Invoke(new ActionRef<string, TextBox>(AppendTextBox), value, textBox);
            return;
        }
        textBox.Text += value;
    }

我得到的结果基本上是这样的:

[10:08:56] - (0) OK
[10:08:56] - (0) OK
[10:09:23] - (0) OK
[10:09:23] - (0) OK
[10:09:49] - (0) OK
[10:09:50] - (0) OK
[10:10:15] - (0) OK
[10:10:16] - (0) OK
etc

据我所知,在服务器端没有限制。我对并行/多任务世界相对来说是个新手。有没有其他方法可以做到这一点?我错过了什么吗?
(为了清晰起见,我简化了所有的代码,我相信提供的代码足以描述上述场景。我也没有发布应用程序代码,但这是一个简单的WinForms屏幕,只是为了调用和显示结果。如果任何代码在某种程度上是相关的,请告诉我,我也可以编辑和发布它。)
提前感谢!
编辑1:我检查了服务器日志,它是两个两个地接收请求,所以它确实是与发送请求有关,而不是接收请求。可能是与框架管理请求/连接的方式有关的网络问题/限制?或者是与网络有关的问题(与.net无关)?
编辑2:忘了提一下,它是一个SOAP Web服务。
EDIT 3:我发送的一个属性(内部数据)需要为每个请求更改。
编辑4:我注意到,如果相关的话,每对请求之间总是有大约25秒的间隔。

xwbd5t1u

xwbd5t1u1#

我建议不要重新发明轮子,而只使用现有的解决方案之一:
1.最明显的选择:如果您的VisualStudio许可证允许您使用MSLoadTestingFramework,则很可能您甚至不必编写一行代码:How to: Create a Web Service Test

  1. SoapUI是一个免费的开源Web服务测试工具,它有一些有限的load testing capabilities
    1.如果由于某些原因SoapUI不适合(例如,您需要从多个主机以集群模式运行负载测试,或者您需要更增强的报告功能),则可以使用Apache JMeter-免费和开源的多协议负载测试工具,它也支持web services load testing
wmvff8tz

wmvff8tz2#

创建负载测试而不编写自己项目的一个很好的解决方案是使用此服务https://loader.io/targets
它是免费的小测试,你可以POST参数,标题,...你有一个很好的报告。

8i9zcol2

8i9zcol23#

“一次两个请求”不是connectionManagement上默认的maxconnection=2限制的结果吗?

<configuration>  
  <system.net>  
    <connectionManagement>  
      <add address = "http://www.contoso.com" maxconnection = "4" />  
      <add address = "*" maxconnection = "2" />  
    </connectionManagement>  
  </system.net>  
</configuration>
vktxenjb

vktxenjb4#

我最喜欢的负载测试库是NBomber。它有一个简单而强大的API,真实的用户模拟,并提供了关于延迟和每秒请求数的HTML报告。我用它来测试我的API,并写了一个article来说明我是如何做的。

相关问题