2015-06-17 37 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從多臺機器執行您的測試計劃。

相關問題