2012-05-04 16 views
11

Ya sé la respuesta a esto, pero quería compartir con la comunidad ya que NO está documentado por Microsoft.Servidor 2008 RC2, IIS 7.5, ASP.NET y peticiones en cola Rendimiento bajo

El escenario: una oleada de tráfico golpea su sitio web IIS 7.5 ASP.NET, y observa que las solicitudes comienzan a hacer cola. El rendimiento del sitio se ralentiza, pero tiene mucha CPU y RAM disponibles.

Este es el problema que vimos recientemente con un sitio que realizó un montón de llamadas internas al servicio web. Una revisión de salud interna comenzaría el tiempo de espera, lo que haría que este servidor abandonara nuestro clúster. (Sin embargo, este servidor es el más potente hardware del montón ...)

Respuesta

12

Después de buscar en todo el Internet, me encontré con los siguientes artículos de Microsoft que se relacionan con el problema:

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

Este artículo ofrece algunos consejos excelentes para ajustar el rendimiento, sin embargo, no menciona algunos techos MUY importantes con los que nos encontramos.

La solución para nosotros fue modificar nuestra machine.config, y llenar los siguientes nodos 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> 

propósito que establece algunos de estos números para "xxx", ya que dependen de su hardware.

En el artículo anterior de KB, Microsoft sugiere algunas ecuaciones para determinar estos valores. Sin embargo, no mencionan que el valor máximo para estos números es el tamaño de un INT, o 32767.

Así, los CORRECTO ecuaciones para calcular estos fuera son los siguientes:

  • maxWorkerThreads: 32767/#Cores
    • En nuestro caso, tenemos un servidor de 24 núcleos. Por lo tanto, nuestro valor maxWorkerThreads está ajustado para entrada: 1365. Cualquier número que se traduce en un entero mayor que 32767, el servidor fijará los maxWorkerThreads a 32767.
  • maxIoThreads: Igual que maxWorkerThreads (32767/#Cores)
  • minWorkerThreads: maxWorkerThreads/2
    • Esto era un asunto difícil. Si se excedió un valor entero MÁS GRANDE que 32767 (ya pesar de lo que dice el artículo de KB, este número se multiplica por la cantidad de núcleos que tiene) y, a diferencia del valor "máximo" , el valor predeterminado es el número de núcleos en su máquina! En nuestro caso, esto se estaba estableciendo en 24 (porque establecimos un valor arbitrariamente alto para el mínimo), y eso era MATAR el rendimiento en nuestro servidor.
  • minIoThreads: Lo mismo que minWorkerThreads
  • minFreeThreads: 88 * #Cores (tomada directamente del artículo de KB)
  • minLocalRequestFreeThreads: 76 * #Cores (tomada directamente del artículo de KB)

Esta solución no es para todos, y solo debe utilizarse si cumple con los criterios del artículo de KB.

Otra herramienta que utilizamos para ayudarnos a diagnosticar esto fue una página .ASPX sin código subyacente que pudimos tirar en cualquier servidor (sin restablecer el grupo de aplicaciones). Esta página usa la reflexión para indicarle qué está sucediendo realmente en el grupo de subprocesos y a qué se refieren los valores de estos ajustes en su servidor.

<%@ 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> 
+0

¿Por qué maxWorkerThreads sería inversamente proporcional a #Cores? es decir, cuantos más núcleos tenga maxWorkerThreads es menor. Tiene más sentido para mí que maxWorkerThreads sea x * #Cores, digamos maxWorkerThreads = 16 * #Cores. – DavidF

+0

¿Qué tan seguro está de que minWorkerThreads y minIoThreads se multiplican por la cantidad de núcleos? ¿Eso es específicamente para .net 4.5? –

+0

Aparentemente confirmado aquí - https://msdn.microsoft.com/en-us/library/system.web.configuration.processmodelsection.minworkerthreads(v=vs.100).aspx –

Cuestiones relacionadas