.NET 4.5 HTTPWebRequest - 具有大量同时HTTPS POST请求的间歇性减速

时间:2014-05-06 16:19:08

标签: .net https httpwebrequest webrequest

我有大量(50+)个线程,它们向Web api发出HTTPS POST请求,以便尽可能快地轮询不同的数据集。它的工作时间很好,但是对于另一半,应用程序使用的带宽会显着下降。

更新1 下面列出的代码不再是当前的,它是根据Domin8urMind推荐修改的。

所以我看了fiddler的所有流量。一旦开始减速,我会注意到我的客户端建立了新的HTTPS隧道,并且在建立新隧道后减速结束。在程序首次启动时建立的50多个隧道只需要大约1秒即可建立,但在减速过程中需要大约30秒来建立所有隧道。这种重建/减速似乎就像每2分钟钟表工作一样。

此外,我注意到CDN位于我的客户端和服务器之间,并且它确实具有DoS保护。我不确定这个性能问题是与我的代码有关,还是与CDN有关。

所以我想我现在的问题是:

  • 在启用保持活动和流水线功能的情况下,在什么条件下关闭HTTPWebRequest的HTTPS连接?
  • 为什么要重新建立这些连接需要这么长时间?

myMethod的

private static string myMethod(string method, Dictionary<string, string> paramList = null, int maxRetryCount = 1)
{
    System.Net.ServicePointManager.Expect100Continue = false;
    System.Net.ServicePointManager.DefaultConnectionLimit = 400;
    System.Net.ServicePointManager.UseNagleAlgorithm = false;

    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("My URL");
    String postData = "My POST Data"

    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = postData.Length;
    request.Method = "POST";
    request.Timeout = 1000;
    request.Headers.Add("Accept-Encoding", "gzip,deflate");
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    request.Proxy = null;

    try
    {
        Stream stream = request.GetRequestStream();
        stream.Write(postData, 0, postData.Length);
        stream.Close();

        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        Stream responseStream = response.GetResponseStream();
        Stream decompressedStream = null;
        if (response.ContentEncoding.ToLower().Contains("gzip"))
            decompressedStream = new GZipStream(responseStream, CompressionMode.Decompress);
        else if (response.ContentEncoding.ToLower().Contains("deflate"))
            decompressedStream = new DeflateStream(responseStream, CompressionMode.Decompress);
        else
            decompressedStream = responseStream;

        StreamReader postreqreader = new StreamReader(decompressedStream);
        var json = postreqreader.ReadToEnd();

        postreqreader.Close();
        decompressedStream.Close();
        responseStream.Close();

        return json;
    }
    catch (Exception e)
    {
        if(e.Message != "The operation has timed out")
            Console.Write("\nGot exception " + e.Message + " " + e.StackTrace + "\n\n\n");
    }
    return null;
}

}

例外1

Got exception The request was aborted: The request was canceled.    at System.Ne
t.GZipWrapperStream.Read(Byte[] buffer, Int32 offset, Int32 size)
   at System.IO.StreamReader.ReadBuffer()
   at System.IO.StreamReader.ReadToEnd()
   at myMethod in myFile:line 337

第337行是“var json = postreqreader.ReadToEnd();”

例外2

Got exception Safe handle has been closed    at System.Runtime.InteropServices.S
afeHandle.DangerousAddRef(Boolean& success)
   at System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolea
n& success)
   at System.Net.UnsafeNclNativeMethods.OSSOCK.setsockopt(SafeCloseSocket socket
Handle, SocketOptionLevel optionLevel, SocketOptionName optionName, Int32& optio
nValue, Int32 optionLength)
   at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, S
ocketOptionName optionName, Int32 optionValue, Boolean silent)
   at System.Net.Sockets.NetworkStream.SetSocketTimeoutOption(SocketShutdown mod
e, Int32 timeout, Boolean silent)
   at System.Net.ConnectStream.DrainSocket()
   at System.Net.ConnectStream.CloseInternal(Boolean internalCall, Boolean abort
ing)
   at System.Net.ConnectStream.System.Net.ICloseEx.CloseEx(CloseExState closeSta
te)
   at System.Net.HttpWebRequest.SetAndOrProcessResponse(Object responseOrExcepti
on)
   at System.Net.ConnectionReturnResult.SetResponses(ConnectionReturnResult retu
rnResult)
   at System.Net.Connection.ReadComplete(Int32 bytesRead, WebExceptionStatus err
orStatus)
   at System.Net.Connection.SyncRead(HttpWebRequest request, Boolean userRetriev
edStream, Boolean probeRead)
   at System.Net.ConnectStream.ProcessWriteCallDone(ConnectionReturnResult retur
nResult)
   at System.Net.HttpWebRequest.CheckDeferredCallDone(ConnectStream stream)
   at System.Net.HttpWebRequest.GetResponse()
   at myMethod in myFile:line 325

第325行是“HttpWebResponse response =(HttpWebResponse)request.GetResponse();”

1 个答案:

答案 0 :(得分:3)

我建议您使用“using”子句更改代码,该子句将正确关闭连接,例如:

HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create("My URL");

using (HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse())
{
  using (Stream stream = httpWebResponse.GetResponseStream())
  {
    using (StreamReader reader = new StreamReader(stream))
    {
      ...
    }
  }
}

您现有循环遇到的问题是,当您捕获异常时,连接没有正确处理,您需要等待垃圾收集器清理这些连接才能创建另一个连接即可。

我怀疑那是你的延迟。您可以通过观察perfmon中的.net GC计数器来验证这一点,如果'%in GC'在这些“减速”期间出现尖峰,那么您就有了罪魁祸首。