web-dev-qa-db-ja.com

なぜIISスレッドは通常のCLRスレッドと比較してそれほど貴重なのですか?

私は AsyncControllersについて読む ASP.NET MVCです。

それらが存在する唯一の理由は、IISスレッドを保存できる一方で、長時間実行されている作業を通常のCLRスレッドに委任することであるため、安価であるようです。

ここにいくつか質問があります:

  • なぜこれらのIISスレッドは、非同期コントローラーをサポートするために構築されたこのアーキテクチャ全体を正当化するのに費用がかかるのですか?
  • 私のIISアプリケーションプールで実行されているスレッド数IISスレッドを知っている/構成する方法?
43
André Pena

ASP.NETは、.NETスレッドプールのスレッドを使用して要求を処理します。スレッドプールは、スレッドの初期化コストが既に発生したスレッドのプールを維持します。したがって、これらのスレッドは簡単に再利用できます。 .NETスレッドプールも自己調整されます。 CPUやその他のリソースの使用率を監視し、必要に応じて新しいスレッドを追加したり、スレッドプールサイズを調整します。通常、作業を実行するためにスレッドを手動で作成することは避けてください。代わりに、スレッドプールのスレッドを使用します。同時に、スレッドプールの枯渇やHTTPリクエストの拒否にすぐにつながる可能性のある長時間のブロッキング操作をアプリケーションが実行しないようにすることが重要です。

ディスクI/O、Webサービス呼び出しはすべてブロックされています。非同期呼び出しを使用して最適化するのが最適です。非同期呼び出しを行うと、asp.netはスレッドを解放し、コールバック関数が呼び出されたときに要求が別のスレッドに割り当てられます。

設定できるスレッドの数を設定するには:

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

参照: ASP.NET Thread Usage on IIS 7.5、IIS 7.0、and IIS 6. =

これらは Microsoftのベストプラクティスが推奨する の設定です。

  • maxconnectionを12 * CPUの数に設定します。この設定は、クライアントから開始できる発信HTTP接続の最大数を制御します。この場合、ASP.NETがクライアントです。 maxconnectionを12 * CPUの数に設定します。
  • maxIoThreadsを100に設定します。この設定は、.NETスレッドプール内のI/Oスレッドの最大数を制御します。この数は、使用可能なCPUの数で自動的に乗算されます。 maxloThreadsを100に設定します。
  • maxWorkerThreadsを100に設定します。この設定は、スレッドプール内のワーカースレッドの最大数を制御します。この数は、使用可能なCPUの数で自動的に乗算されます。 maxWorkerThreadsを100に設定します。
  • minFreeThreadsを88 * CPUの数に設定します。この設定は、スレッドプール内の使用可能なスレッドの数がこの設定の値を下回る場合、すべての着信要求をキューに入れるためにワーカープロセスによって使用されます。この設定は、maxWorkerThreads-minFreeThreadsに同時に実行できるリクエストの数を効果的に制限します。 minFreeThreadsを88 * CPUの数に設定します。これにより、同時リクエストの数が12に制限されます(maxWorkerThreadsが100であると仮定)。
  • minLocalRequestFreeThreadsを76 * CPUの数に設定します。この設定は、スレッドプール内の使用可能なスレッドの数がこの数を下回った場合、ローカルプロセス(WebアプリケーションがローカルWebサービスに要求を送信する場所)からの要求をキューに入れるためにワーカープロセスによって使用されます。この設定はminFreeThreadsに似ていますが、ローカルコンピューターからのlocalhost要求にのみ適用されます。 minLocalRequestFreeThreadsを76 * CPUの数に設定します。

:このセクションで提供される推奨事項はルールではありません。それらは出発点です。

アプリケーションに最適なものを見つけるには、アプリケーションのベンチマークを行う必要があります。

48
nunespascal

IISスレッドは、デフォルトのスレッドプールから取得されます。これは、プロセッサコアの数に基づいてデフォルトで制限されています。このスレッドプールキューがバックアップされると、IISは要求への応答を停止します。非同期コードを使用すると、非同期操作の実行中にスレッドプールスレッドをプールに戻すことができ、IISが全体としてより多くのリクエストを処理できるようになります。

一方、自分で新しいスレッドを生成する場合、スレッドプールスレッドは使用されません。未チェックの数の独立したスレッドを生成することも問題になる可能性があるため、IISスレッドプールの問題を完全に解決することはできません。通常、非同期IOがどちらの方法でも推奨されます。

スレッドプール内のスレッド数の変更については、 こちらで確認してください 。ただし、おそらくreally回避する必要があります。

6
Chris

私たちのウェブサービスは時々サービスを提供する必要があります100リクエスト/秒、残りの時間は1リクエスト/秒です。 Analazyng IIS私たちが見つけたログは、そのようなコールを処理するためにバーストが発生したとき、28sかかりました。

Microsoftのベストプラクティス を適用すると、@ nunespascalが引用したように、この場合は1sに大幅に時間を短縮しました。

以下は、運用サーバーを展開するときに現在使用しているPowershellスクリプトです。 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年のブログ Stuart Brierleyによる記事 から寄せられました。2008R2から2016までのWindows Serverでテストを成功させました。

4

実際に リンクした記事 で書かれていることは正しくありません。 「スーパーコストの高いIISワーカースレッド」を解放し、バックグラウンドで他の「安いスレッド」を使用する非同期パターンはありません。

非同期パターンは、単にスレッドを解放するためのものです。スレッドを必要としないシナリオで(そして、ローカルマシンでなくても最高です)、このシナリオの恩恵を受けることができます。

2つのシナリオ例(両方ともI/O)に名前を付けることができます。

最初:

  1. BeginRequest
  2. 非同期ファイルの読み取りを開始
  3. ファイルの読み取り中はスレッドは必要ありません。他のリクエストで使用できます。
  4. ファイルの読み取りが終了します-アプリプールからスレッドを取得します。
  5. 要求は終了します。

そしてほぼ同じ秒:

  1. BeginRequest
  2. WCFサービスへの非同期呼び出しを開始します。
  3. マシンを離れることができ、スレッドは必要ありません。他のリクエストで使用できます。
  4. リモートサービスから応答を受け取ります-アプリプールからスレッドを取得して続行します。
  5. 要求は終了します。

通常、msdnを読むのは安全です。非同期パターンに関する情報を取得できます here

4
Grzegorz W