Ответ 1
После поиска в Интернете я нашел следующие статьи от Microsoft, которые относятся к проблеме:
В этой статье приводятся некоторые полезные советы по настройке производительности, однако не упоминается несколько ОЧЕНЬ важных потолков, в которые мы столкнулись.
Решение для нас состояло в том, чтобы изменить наш файл 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", так как они зависят от вашего оборудования.
Из статьи KB выше, Microsoft предлагает некоторые уравнения для определения этих значений. Однако они не упоминают, что значение MAXIMUM для этих чисел - это размер INT или 32767.
Итак, уравнения ПРАВИЛЬНЫЕ для их определения выглядят следующим образом:
- maxWorkerThreads: 32767/#Cores
- В нашем случае у нас есть 24-ядерный сервер. Итак, наше значение maxWorkerThreads правильно установлено: 1365. Любое число, которое приводит к целому LARGER, чем 32767, сервер установит maxWorkerThreads на 32767.
- maxIoThreads: То же, что и maxWorkerThreads (32767/#Cores)
- minWorkerThreads: maxWorkerThreads/2
- Это было сложно. Если одно превысило целочисленное значение LARGER, чем 32767 (и, несмотря на то, что сказано в статье в KB, это число IS умножается на количество ядер, которые у вас есть), и в отличие от значения "max" это значение по умолчанию соответствует количеству ядер на вашем компьютере! В нашем случае это устанавливалось равным 24 (потому что мы установили произвольно высокое значение для min), и это было УБЫТЬ производительность на нашем сервере.
- minIoThreads: То же, что и minWorkerThreads
- minFreeThreads: 88 * #Cores (взято непосредственно из статьи KB)
- minLocalRequestFreeThreads: 76 * #Cores (взято непосредственно из статьи KB)
Это решение не для всех и должно использоваться только в том случае, если вы отвечаете критериям в статье базы знаний.
Еще один инструмент, который мы использовали, помогая нам диагностировать это, - это страница .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>