asp.net - Server 2008 RC2、IIS 7.5、ASP.NET 和请求排队性能不佳

标签 asp.net performance iis threadpool

我已经知道这个问题的答案,但想与社区分享,因为它没有从 Microsoft 记录下来。

场景:流量激增到达您的 IIS 7.5 ASP.NET 网站,您注意到请求开始排队。该站点的性能缓慢到爬行,但您有足够的 CPU 和 RAM 可用。

这是我们最近在一个网站上看到的问题,该网站进行了大量内部网络服务调用。内部运行状况检查将开始超时,这将导致此服务器退出我们的集群。 (然而,这个服务器是最强大的硬件......)

最佳答案

在网上搜索后,我找到了以下微软相关的文章:

知识库 821268:Contention, poor performance, and deadlocks when you make Web service requests from ASP.NET applications

这篇文章提供了一些很好的性能调整技巧,但是它没有提到我们遇到的一些非常重要的天花板。

我们的解决方案是修改我们的 machine.config,并填充以下 XML 节点:

<system.web>
    <processModel autoConfig="false" maxWorkerThreads="xxx" maxIoThreads="xxx" minWorkerThreads="xxx" minIoThreads="xxx" requestQueueLimit="5000" responseDeadlockInterval="00:03:00"/>
    <httpRuntime minFreeThreads="xxx" minLocalRequestFreeThreads="xxx"/>
</system.web>

我特意将其中一些数字设置为“xxx”,因为它们取决于您的硬件。

从上面的知识库文章中,Microsoft 提出了一些计算这些值的公式。但是,他们没有提到这些数字的 MAXIMUM 值是 INT 的大小,即 32767。

所以,正确 计算这些的方程式如下:
  • maxWorkerThreads :32767/#核心
  • 在我们的例子中,我们有一个 24 核的服务器。因此,我们的 maxWorkerThreads 值正确设置为:1365。任何导致整数大于 32767 的数字,服务器都会将 maxWorkerThreads 设置为 32767。
  • maxIoThreads : 与 maxWorkerThreads (32767/#Cores)
  • 相同
  • minWorkerThreads : 最大 worker 线程数/2
  • 这是一个棘手的问题。如果超过一个大于 32767 的整数值(尽管 KB 文章是这样说的,这个数字乘以您拥有的内核数),并且与“max”值不同,这默认为您机器上的内核数!在我们的例子中,它被设置为 24(因为我们为 min 设置了一个任意高的值),这会降低我们服务器的性能。
  • minIoThreads : 与 minWorkerThreads
  • 相同
  • minFreeThreads : 88 * #Cores(直接取自知识库文章)
  • minLocalRequestFreeThreads : 76 * #Cores(直接取自知识库文章)

  • 此解决方案并不适合所有人,只有在满足知识库文章中的条件时才应使用。

    我们用来帮助​​我们诊断这个问题的另一个工具是一个没有代码隐藏的 .ASPX 页面,我们可以在任何服务器上扔掉它(无需重置应用程序池)。此页面使用反射来告诉您线程池中实际发生的事情,以及这些设置的值在您的服务器上呈现的内容。
    <%@ Page Language="C#" %>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <style>
        body { margin: 20pt; padding: 0pt; font-family: Verdana, "san-serif";}
        fieldset { border-radius: 5px; border: none; background-color: #fff; margin: 10pt;}
        fieldset.parent { background-color: #f0f0f0; }
        legend { font-size: 10pt; color: #888; margin: 5pt; }
    
        .ports div { padding: 10pt 0pt 0pt 0pt; clear: both; }
        .ports div:first-child { padding: 0pt; }
        .ports div div { padding: 0pt; clear: none; margin: 1pt; background-color: #eef; display: block; float: left; border: 5pt solid #eef; }
        .ports div div:first-child { border-top-left-radius: 5pt; border-bottom-left-radius: 5pt; background-color: #ccf; border-color: #ccf;}
        .ports div div:last-child { border-top-right-radius: 5pt; border-bottom-right-radius: 5pt; background-color: #ccf; border-color: #ccf; padding: 0pt 10pt 0pt 10pt; }
    </style>
    
    </head>
    <body>
    
    <%
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    
    int worker, workerMIN, workerMAX;
    int port, portMIN, portMAX;
    System.Threading.ThreadPool.GetAvailableThreads(out worker, out port);
    System.Threading.ThreadPool.GetMinThreads(out workerMIN, out portMIN);
    System.Threading.ThreadPool.GetMaxThreads(out workerMAX, out portMAX);
    
     %>
    
    <fieldset class="parent">
    <legend>Thread Information</legend>
    
    <fieldset>
        <legend>Worker Threads</legend>
        <div class="ports">
            <div>
                <div>Min: <%=workerMIN %></div>
                <div>Current: <%=workerMAX - worker %></div>
                <div>Max: <%=workerMAX %></div>
            </div>
        </div>
    </fieldset>
    
    <fieldset>
        <legend>Completion Port Threads</legend>
        <div class="ports">
            <div>
                <div>Min: <%=portMIN %></div>
                <div>Current: <%=portMAX - port %></div>
                <div>Max: <%=portMAX %></div>
            </div>
        </div>
    </fieldset>
    
    <fieldset>
        <legend>Request Queue Information</legend>
        <div class="ports">
    
    <%
    
    
    var fi = typeof(HttpRuntime).GetField("_theRuntime", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static).GetValue(null);
    var rq = typeof(HttpRuntime).GetField("_requestQueue", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(fi);
    var fields = rq.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    
    foreach (var field in fields)
    {
        string name = field.Name;
        string value = "";
    
        switch (name)
        {
            case "_localQueue":
            case "_externQueue":
                System.Collections.Queue queue = field.GetValue(rq) as System.Collections.Queue;
                value = queue.Count.ToString();
                break;
    
            default:
                value = field.GetValue(rq).ToString();
                break;
        }
    
        %>
            <div>
                <div><%=name %></div>
                <div><%=value %></div>
            </div>
        <%
        //Response.Write(string.Format("{0}={1}<br/>", name, value));
    }   
    
    %>
        </div>
    </fieldset>
    </fieldset>
    
    
    
    </body></html>
    

    关于asp.net - Server 2008 RC2、IIS 7.5、ASP.NET 和请求排队性能不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10455455/

    相关文章:

    python - 如何在Python中将一维径向轮廓转换为二维数组

    php - NewRelic PHP 代理增加了多少开销?

    c# - 如何使用 window.open() 传递变量?

    asp.net - 如何在 IIS 8 中启用 WebSockets?

    asp.net - 在asp.net中缓存 key 长度

    performance - R 中的执行效率与程序员效率

    iis - WinDbg 符号代理

    asp.net - 如何配置 IIS 以接受 POST 请求?

    iis - 当 web.config 中的allowSessionState 设置为 false 时,HTTP/1.1 新应用程序失败

    asp.net - asp.net 的文档管理系统