c# - HttpWebResponse 不会针对并发出站请求进行扩展

标签 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();
    }
}

如果我在本地开发机器 (Windows 7) 的 Visual Studio Web 服务器上运行应用程序,我可以增加 numThreads 并接收相同的平均响应时间,无论是 1 个“用户”还是 100 个,变化都很小。

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

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

我们构建了一个类似的 PHP 应用程序,并在 Mono 中部署了相同的请求和相应的响应。

我已经遍历了我能想到的针对 Mono 和 Apache 的每一个配置设置,两种环境之间唯一不同的设置(至少在代码中)是有时 ServicePoint SupportsPipelining=false 在 Mono 中,而它是从我的机器上看是真的。

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

要么我和我的团队忽略了一些重要的事情,要么这是 Mono 中的某种错误。

最佳答案

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

首先,为了符合 HTTP 规范,服务点默认只允许两个到给定主机的并发连接。这可以通过将静态属性 ServicePointManager.DefaultConnectionLimit 设置为更高的值来覆盖。看这个MSDN页面了解更多详情。看起来您已经在为单个服务点本身解决这个问题,但由于服务点级别的并发锁定方案,这样做可能会导致瓶颈。

其次,ServicePoint 类本身似乎存在锁定粒度问题。如果反编译并查看 lock 关键字的源代码,您会发现它使用实例本身进行同步,并且在很多地方都是这样做的。随着服务点实例在给定主机的 Web 请求之间共享,根据我的经验,随着打开更多 HttpWebRequests 并导致其扩展性很差,这往往会成为瓶颈。第二点主要是个人观察和源头探索,所以要持保留态度;我不认为它是权威来源。

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

关于c# - HttpWebResponse 不会针对并发出站请求进行扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9997143/

相关文章:

javascript - 在apache上使用nodeJS发送文件

linux - 执行不带扩展名的 CGI 文件

ruby-on-rails - Linux、Rails、Mono C#、No-SQL 设置

c# - linq Group By 并获取第一个和最后一个记录

c# - C# 中的持久工作队列

apache - 如何在 httpd.conf 中使用一个 IP 地址在 CentOS Apache 上设置多个 SSL 通配符证书

.net - 单声道中的 P/调用

c# - 如何检测正在使用哪个垃圾收集器?

c# - 现有MVC5应用程序中Noda Time的实现策略

c# - 'Enums' 类中不允许代码优先枚举? (英孚 5)