Подтвердить что ты не робот

Почему IIS-потоки столь ценны по сравнению с обычными потоками CLR?

Я чтение об AsyncControllers в ASP.NET MVC.

Похоже, что единственная причина, по которой они существуют, заключается в том, что нити IIS могут быть сохранены, а работа с длительностью работы делегирована в обычные потоки CLR, которые кажутся более дешевыми.

У меня есть несколько вопросов здесь:

  • Почему эти потоки IIS настолько дороги, чтобы оправдать всю эту архитектуру, построенную для поддержки асинхронных контроллеров?
  • Как узнать/настроить, сколько потоков IIS выполняется в пуле приложений IIS?
4b9b3361

Ответ 1

ASP.NET обрабатывает запросы, используя потоки из пула потоков .NET. Пул потоков поддерживает пул потоков, которые уже понесли затраты на инициализацию потока. Поэтому эти потоки легко использовать повторно. Пул потоков .NET также самонастраивается. Он контролирует использование ресурсов процессора и других ресурсов и добавляет новые потоки или уменьшает размер пула потоков по мере необходимости. Обычно вы должны избегать создания потоков вручную для выполнения работы. Вместо этого используйте потоки из пула потоков. В то же время важно обеспечить, чтобы ваше приложение не выполняло длительные операции блокировки, которые могли бы быстро привести к голоданию пула потоков и отбросить HTTP-запросы.

Диск-ввод/вывод, вызовы веб-службы блокируются. Лучше всего оптимизировать использование асинхронных вызовов. Когда вы выполняете асинхронный вызов, asp.net освобождает ваш поток, и запрос будет назначен другому потоку при вызове функции обратного вызова.

Чтобы настроить количество потоков, которые вы можете установить:

<system.web>
    <applicationPool maxConcurrentRequestsPerCPU="50" maxConcurrentThreadsPerCPU="0" requestQueueLimit="5000"/>
</system.web>

Обратитесь: Использование потоков ASP.NET для IIS 7.5, IIS 7.0 и IIS 6.0

Это параметр, который Рекомендуемые рекомендации Microsoft:

  • Установите максимальное соединение на 12 * # процессоров. Этот параметр управляет максимальным количеством исходящих HTTP-соединений, которые вы можете инициировать от клиента. В этом случае ASP.NET является клиентом. Установите максимальное соединение на 12 * # процессоров.
  • Установите maxIoThreads на 100. Этот параметр управляет максимальным количеством потоков ввода-вывода в пуле потоков .NET. Это число автоматически умножается на количество доступных ЦП. Установите maxloThreads на 100.
  • Установите maxWorkerThreads на 100. Этот параметр определяет максимальное количество рабочих потоков в пуле потоков. Затем это число автоматически умножается на количество доступных ЦП. Установите maxWorkerThreads на 100.
  • Установите minFreeThreads на 88 * # процессоров. Этот параметр используется рабочим процессом для очереди всех входящих запросов, если количество доступных потоков в пуле потоков падает ниже значения для этого параметра. Этот параметр эффективно ограничивает количество запросов, которые могут запускаться одновременно с maxWorkerThreads - minFreeThreads. Установите minFreeThreads на 88 * # процессоров. Это ограничивает количество одновременных запросов до 12 (при условии, что maxWorkerThreads равно 100).
  • Установите minLocalRequestFreeThreads для 76 * # процессоров. Этот параметр используется рабочим процессом для очереди запросов с localhost (где веб-приложение отправляет запросы на локальную веб-службу), если количество доступных потоков в пуле потоков падает ниже этого числа. Этот параметр похож на minFreeThreads, но он применяется только к запросам localhost с локального компьютера. Установите minLocalRequestFreeThreads на 76 * # процессоров.

Примечание. Рекомендации, приведенные в этом разделе, не являются правилами. Они являются отправной точкой.

Вам нужно будет сравнить ваше приложение, чтобы найти то, что лучше всего подходит для вашего приложения.

Ответ 2

Нити IIS берутся из пула потоков по умолчанию, который ограничен по умолчанию на основе количества процессорных ядер. Если эта очередь пула потоков будет скопирована, IIS перестанет отвечать на запросы. Используя асинхронный код, поток пула потоков может быть возвращен в пул, пока выполняется асинхронная операция, что позволяет IIS обслуживать больше запросов в целом.

С другой стороны, нереста нового потока по своему усмотрению не использует поток потока потоков. Проблема с неконтролируемым числом независимых потоков также может быть проблемой, поэтому она не устраняет все проблемы с пулом потоков IIS. Async IO обычно является предпочтительным в любом случае.

Что касается изменения количества потоков в пуле потоков, здесь проверьте. Однако вы, вероятно, должны действительно избегать этого.

Ответ 3

На самом деле то, что написано в статье, которую вы связали, неверно. Асинхронный шаблон не существует, чтобы освободить "сверхзатратные рабочие потоки IIS" и использовать в фоновом режиме некоторые другие "дешевые потоки".

Асинхронный шаблон просто освобождает потоки. Вы можете извлечь выгоду из этого в сценариях, где вам не нужны ваши потоки (и лучше всего даже не ваша локальная машина).

Я могу назвать два примера сценариев (оба ввода-вывода):

Во-первых:

  • BeginRequest
  • Начать чтение файла aync
  • во время чтения файла вам не нужен ваш поток, поэтому другие запросы могут его использовать.
  • Окончание чтения файла - вы получаете поток из пула приложений.
  • Запрос завершается.

И почти идентичная секунда:

  • BeginRequest
  • Начните асинхронный вызов службы WCF.
  • Мы можем оставить нашу машину и не нуждаемся в нашем потоке, поэтому другие запросы могут ее использовать.
  • Мы получаем ответ от удаленного сервиса - мы получаем поток из пула приложений для продолжения.
  • Запрос завершается.

Обычно безопасно читать msdn. Вы можете получить информацию об асинхронном шаблоне здесь.

Ответ 4

Наш веб-сервис должен время от времени обслуживать 100 запросов/секунду, а остальное время - 1 запрос/секунда. В журналах Analazyng IIS мы выяснили, что для выполнения таких вызовов потребовалось около 28 с.

Применение Лучшие рекомендации Microsoft, как указано в @nunespascal , резко сократило время до 1 с в нашем случае.

Ниже приведен Powershell script, который мы используем при развертывании наших производственных серверов. Он обновляет machine.config с учетом количества логических процессоров.

<# Get and backup current machine.config #>
$path = "C:\Windows\Microsoft.Net\Framework\v4.0.30319\Config\machine.config";
$xml = [xml] (get-content($path));
$xml.Save($path + "-" + (Get-Date -Format "yyyyMMdd-HHmm" ) + ".bak");

<# Get number of physical CPU #>
$physicalCPUs = ([ARRAY](Get-WmiObject Win32_Processor)).Count;

<# Get number of logical processors #>
$logicalProcessors = (([ARRAY](Get-WmiObject Win32_Processor))[0] | Select-Object "numberOfLogicalProcessors").numberOfLogicalProcessors * $physicalCPUs;

<# Set Number of connection in system.net/connectionManagement #>
$systemNet =  $xml.configuration["system.net"];
if (-not $systemNet){
    $systemNet = $xml.configuration.AppendChild($xml.CreateElement("system.net"));
}

$connectionManagement = $systemNet.connectionManagement;
if (-not $connectionManagement){

    $connectionManagement = $systemNet.AppendChild($xml.CreateElement("connectionManagement"));
}

$add = $connectionManagement.add;
if(-not $add){
    $add = $connectionManagement.AppendChild($xml.CreateElement("add")) ;
}
$add.SetAttribute("address","*");
$add.SetAttribute("maxconnection", [string]($logicalProcessors * 12) );

<# Set several thread settings in system.web/processModel #>
$systemWeb =  $xml.configuration["system.web"];
if (-not $systemWeb){
    $systemWeb = $xml.configuration.AppendChild($xml.CreateElement("system.web"));
}

$processModel = $systemWeb.processModel;
if (-not $processModel){
    $processModel = $systemWeb.AppendChild($xml.CreateElement("processModel"));
}
$processModel.SetAttribute("autoConfig","true");
$processModel.SetAttribute("maxWorkerThreads","100");
$processModel.SetAttribute("maxIoThreads","100");
$processModel.SetAttribute("minWorkerThreads","50");
$processModel.SetAttribute("minIoThreads","50");

<# Set other thread settings in system.web/httRuntime #>
$httpRuntime = $systemWeb.httpRuntime;
if(-not $httpRuntime){
    $httpRuntime = $systemWeb.AppendChild($xml.CreateElement("httpRuntime"));
}
$httpRuntime.SetAttribute("minFreeThreads",[string]($logicalProcessors * 88));
$httpRuntime.SetAttribute("minLocalRequestFreeThreads",[string]($logicalProcessors * 76));

<#Save modified machine.config#>
$xml.Save($path);

Это решение пришло к нам из блога статьи, написанной Стюартом Бриерли в 2009 году. Мы успешно протестировали его с Windows Server с 2008 R2 до 2016 года.