HttpWebResponse不会扩展并发出站请求

era*_*end 12 c# apache mono httpwebresponse servicepoint

我有一个用C#编写的ASP.NET 3.5服务器应用程序.它使用HttpWebRequest和HttpWebResponse向REST API发出出站请求.

我已经设置了一个测试应用程序来在不同的线程上发送这些请求(模糊地模仿服务器的并发性).

请注意,这更像是单声道/环境问题,而不是代码问题; 所以请记住,下面的代码不是逐字的; 只是功能位的剪切/粘贴.

这是一些伪代码:

// threaded client piece
int numThreads = 1;
ManualResetEvent doneEvent;

using (doneEvent = new ManualResetEvent(false))
        {

            for (int i = 0; i < numThreads; i++)
            {

                ThreadPool.QueueUserWorkItem(new WaitCallback(Test), random_url_to_same_host);

            }
            doneEvent.WaitOne();
        }

void Test(object some_url)
{
    // setup service point here just to show what config settings Im using
    ServicePoint lgsp = ServicePointManager.FindServicePoint(new Uri(some_url.ToString()));

        // set these to optimal for MONO and .NET
        lgsp.Expect100Continue = false;
        lgsp.ConnectionLimit = 100;
        lgsp.UseNagleAlgorithm = true;
        lgsp.MaxIdleTime = 100000;        

    _request = (HttpWebRequest)WebRequest.Create(some_url);


    using (HttpWebResponse _response = (HttpWebResponse)_request.GetResponse())
    {
      // do stuff
    } // releases the response object

    // close out threading stuff

    if (Interlocked.Decrement(ref numThreads) == 0)
    {
        doneEvent.Set();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我在Visual Studio Web服务器上的本地开发计算机(Windows 7)上运行该应用程序,我可以启动numThreads并获得相同的平均响应时间,只需要1"user"或100即可获得最小的变化.

在Mono 2.10.2环境中发布应用程序并将其部署到Apache2,响应时间几乎呈线性增长.(即,1个线程= 300毫秒,5个线程= 1500毫秒,10个线程= 3000毫秒).无论服务器端点(不同的主机名,不同的网络等)如何,都会发生这种情况.

使用IPTRAF(和其他网络工具),似乎应用程序只打开1或2个端口来路由所有连接,其余响应必须等待.

我们构建了一个类似的PHP应用程序,并在Mono中使用相同的请求进行部署,并且响应可以适当缩放.

我已经完成了我能想到的Mono和Apache的每一个配置设置,并且两个环境之间的唯一设置(至少在代码中)是有时候Mono中的ServicePoint SupportsPipelining = false,而我的确是如此机.

似乎ConnectionLimit(默认值为2)由于某种原因未在Mono中更改,但我在代码和指定主机的web.config中将其设置为更高的值.

无论是我和我的团队都忽略了重要的事情,或者这是Mono中的某种错误.

Jes*_*ire 8

我相信你在这个问题上遇到了瓶颈HttpWebRequest.Web请求每个都使用.NET框架内的公共服务点基础结构.这似乎是为了允许重用对同一主机的请求,但根据我的经验导致两个瓶颈.

首先,默认情况下,服务点仅允许与给定主机的两个并发连接,以便符合HTTP规范.可以通过将static属性ServicePointManager.DefaultConnectionLimit设置为更高的值来覆盖它.有关详细信息,请参阅此MSDN页面.看起来您已经为单个服务点本身解决了这个问题,但由于服务点级别的并发锁定方案,这样做可能会导致瓶颈.

其次,ServicePoint类本身的锁粒度似乎存在问题.如果您反编译并查看lock关键字的源代码,您会发现它使用实例本身进行同步,并在许多地方执行此操作.由于服务点实例在给定主机的Web请求之间共享,根据我的经验,这会导致瓶颈,因为更多HttpWebRequests的打开并导致其扩展性差.第二点主要是个人观察和在源头周围戳,所以拿一粒盐; 我不认为它是权威来源.

不幸的是,在我使用它的时候,我没有找到合理的替代品.既然已经发布了ASP.NET Web API,您可能希望看一下HttpClient.希望有所帮助.


小智 8

我知道这已经很老了但是我把它放在这里,以防它可能会帮助遇到这个问题的其他人.我们遇到了与并行出站HTTPS请求相同的问题.有一些问题在起作用.

第一个问题是,ServicePointManager.DefaultConnectionLimit据我所知,没有改变连接限制.将此设置为50,创建新连接,然后检查新连接的服务点上的连接限制,请执行以下操作:2.将该服务点上的设置设置为50一次似乎可以工作并保留所有最终将通过的连接那个服务点.

我们遇到的第二个问题是线程.单线程池的当前实现似乎每秒最多创建2个新线程.如果您在同一时间开始执行许多并行请求,那么这将是永恒的.为了抵消这种情况,我们尝试将ThreadPool.SetMinThreads设置为更高的数字.无论当前线程数与所需数量之间的差值如何,Mono只会在您进行此调用时创建最多1个新线程.我们能够通过在循环中调用SetMinThreads来解决此问题,直到线程池具有所需数量的空闲线程.

我打开了一个关于后一个问题的错误,因为那是我最有信心的那个没有按预期工作的:https://bugzilla.xamarin.com/show_bug.cgi?id = 7055