执行超过 1000 个 HTTP 请求任务失败
本文关键字:请求 任务 失败 HTTP 1000 执行 | 更新日期: 2023-09-27 17:56:37
我正在尝试加载测试API。我同时执行一个任务,每个任务执行一个HTTP请求。我使用Task.WhenAll(mytasks)
等待所有任务完成。请求如下所示:
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 块,但我想把它留给底层系统......
我想把它留给底层系统...
这不是一个好主意。.NET Framework 在确定 IO 的最佳并行度方面的能力为零。
并行发出这么多请求通常不是一个好主意,因为此处强调的资源可能在此之前已用完。显然,您的后端服务器无法处理这种程度的并行性。它根据消息强行切断您的联系。
仅仅因为我们现在与await
有简单的异步 IO,并不意味着您可以使用 1000 个并行请求向资源发送垃圾邮件。
使用一种常见解决方案以设定的并行度执行一系列异步操作。我喜欢 http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx 但也有一些基于ActionBlock
的解决方案。
正如usr在他的回答中已经指出的那样,您的服务器正在关闭连接,从而导致错误消息:
An existing connection was forcibly closed by the remote host.
你仍然不知道你的瓶颈到底是什么。可能是您的服务器无法处理请求,可能是服务器由于某些速率限制功能而阻止了它们,也可能是由于无法足够快地处理响应并因此保持太多连接打开而导致的压力客户端本身。在能够优化服务之前,您需要收集其他信息。
与其尝试编写自己的压力测试工具,我建议使用一个成熟的工具,比如Apache JMeter。您应该能够生成类似于要运行的测试用例的测试计划。
在某些时候,您将达到单个机器无法模拟的用户计数。有一些服务(如 Redline13)允许您从 EC2 实例运行测试,并为您提供分析结果数据的工具。您还可以使用此 JMeter EC2 脚本从多台计算机执行测试计划。
我前段时间写了这个要点
//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 个请求,但即使这样也是对系统/网络资源的压力测试。