2015-06-17 35 views
3

我试图加载测试API。我正在执行一个任务,每个执行一个HTTP请求。我使用Task.WhenAll(mytasks)等待所有任务完成。请求看起来如下:执行超过1000个HTTP请求任务失败

using (var response = await client.SendAsync(request).ConfigureAwait(false)) 
{ 
    using (var jsonResponse = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) 
    { 
     var jsonSerializer = new DataContractJsonSerializer(typeof(Borders)); 
     var borders = (Borders)jsonSerializer.ReadObject(jsonResponse); 
     return borders; 
    } 
} 

这可以正常工作至少一千个任务。但是,如果我开始更多的则几千元的任务我碰上HttpRequestExceptions

System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host 
    at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult) 
    --- End of inner exception stack trace --- 
    at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar) 
    --- End of inner exception stack trace --- 
    at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult) 
    at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar) 
    --- End of inner exception stack trace --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult() 
    at BusinessLogic.<GetBorder>d__6d.MoveNext() in c:\BusinessLogic.cs:line 757 

所以我的问题:为什么会发生这种情况(超过1000级的任务)?我怎样才能防止这一点?我能明显把我的任务块成块< 1000,但我想离开这个基础系统...

+0

您正在使用IIS在Windows 7或8上进行测试? – Max

+1

例外情况'现有连接被远程主机强行关闭'可能是正在发生的事情的线索。 – Micke

+0

@Max:Windows Server 2008 R2;没有IIS,我正在使用自托管的ASP.NET Web API – Dunken

回答

3

我想离开这个基础系统...

这不是一个好主意。在确定IO的最佳并行度时,.NET Framework没有能力。

通常不是一个好主意,并行发出多个请求,因为这里强调的资源在此之前可能会超出。显然,你的后端服务器不是为了处理这种并行性。它根据消息强行切断你。

仅仅因为我们有容易异步IO与await现在并不意味着您可以用1000个并行请求垃圾邮件您的资源。

使用常用解决方案之一以一定程度的并行性执行一系列异步操作。我喜欢http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx,但也有基于ActionBlock的解决方案。

+0

现在,当我想到它时,你的解释是有道理的......(不要问我为什么没有早点考虑它)。看起来我只是陷入了一个易于使用的API。谢谢! – Dunken

+0

.NET没有内置的简单方法来为每个循环运行异步和给定的DOP。这经常是需要的,并且每周导致堆栈溢出问题。你并不孤单,这个问题。 – usr

0

我写了这个要点前段时间

//PM> Install-Package Rx-Linq 
readonly List<string> _list = new List<string> { "http://www.google.com", "https://www.gmail.com", "http://www.aripaev.ee" }; 
private readonly string format = "[{0}] {1} : {2} [{3}]"; 
[Category("WebClient")] 
[TestCase("sync")] 
public void SynchronousTest(string name) 
{ 
    DateTime start = DateTime.Now; 
    var dict = _list.ToDictionary(o => o, o => new WebClient().DownloadString(new Uri(o))); 
    dict.Keys.ToList().ForEach(o => Console.WriteLine(format, DateTime.Now - start, o, dict[o].Length, name)); 
} 
[Category("WebClient")] 
[TestCase("async")] 
public void AsynchronousTest(string name) 
{ 
    DateTime start = DateTime.Now; 
    var dict = _list.ToDictionary(o => o, async o => await new WebClient().DownloadStringTaskAsync(new Uri(o))); 
    dict.Keys.ToList().ForEach(o => Console.WriteLine(format, DateTime.Now - start, o, dict[o].Result.Length, name)); 
} 
[Category("WebClient")] 
[TestCase("lazy")] 
public void LazyTest(string name) 
{ 
    var start = DateTime.Now; 
    var dict = _list.ToDictionary(o => o, o => new Lazy<string>(() => new WebClient().DownloadString(new Uri(o)))); 
    dict.Keys.ToList().ForEach(o => Console.WriteLine(format, DateTime.Now - start, o, dict[o].Value.Length, name)); 
} 

有了结果如下:

[00:00:00.9520952] http://www.google.com : 51348 [sync] 
[00:00:00.9520952] https://www.gmail.com : 58704 [sync] 
[00:00:00.9520952] http://www.aripaev.ee : 208324 [sync] 

[00:00:00.0010001] http://www.google.com : 51412 [lazy] 
[00:00:00.6550655] https://www.gmail.com : 58664 [lazy] 
[00:00:00.7690769] http://www.aripaev.ee : 208324 [lazy] 

[00:00:00.1430143] http://www.google.com : 51366 [async] 
[00:00:00.3430343] https://www.gmail.com : 58616 [async] 
[00:00:00.5150515] http://www.aripaev.ee : 208324 [async] 

单机/服务器可以处理300-500的并发请求,但即使是一个压力测试系统/网络资源。

3

由于USR在他的回答已经说过,您的服务器关闭连接,导致错误消息:

An existing connection was forcibly closed by the remote host. 

你还是不知道到底是你的瓶颈是什么。可能是因为您的服务器无法处理请求,可能是由于某些速率限制功能导致服务器阻止了它们,也可能是压力客户端本身,因为无法足够快地处理响应,因此保持太多连接打开。您需要收集更多信息才能优化您的服务。

与其试图编写自己的压力测试工具,我建议使用已建立的压力测试工具,如Apache JMeter。您应该能够构建一个类似于您想要运行的测试案例的测试计划。

在某些时候,您将达到用户数量单个机器无法模拟。有服务(如Redline13)可让您从EC2实例运行测试,并为您提供分析结果数据的工具。您也可以使用此JMeter EC2 script从多台机器执行您的测试计划。

相关问题