-
Notifications
You must be signed in to change notification settings - Fork 0
MS_ASPNETConfig
同時実行性を向上させるためのパラメタについて纏める。
サマリすると以下の様になる。
-
IIS 6 以前、IIS 7 以降のクラシック・モード
machine.config に設定を行う。 -
IIS 7 以降のクラシック・モード+.NET 4 以前
MaxConcurrentRequestsPerCPU レジストリに設定を行う。 -
IIS 7 以降の統合モード
-
.NET 3.5 以前
MaxConcurrentRequestsPerCPU レジストリに設定を行う。 -
.NET 3.5 SP1 以降
aspnet.config に設定を行う。
-
補足(この表が本ページの要): 「どこに設定するか」が
IIS のバージョン × パイプライン モード × .NET のバージョンで
変わる、というのが本ページの主題である。一覧にすると次の通り。
IIS モード .NET 設定場所 IIS 6 以前 - 1.1 machine.config(processModel)IIS 6 以前 - 2.0+ 自動構成(通常は変更不要) IIS 7+ クラシック 〜4 以前 レジストリ( MaxConcurrentRequestsPerCPU)IIS 7+ 統合 〜3.5 レジストリ IIS 7+ 統合 3.5 SP1 以降 aspnet.config(applicationPool)「昔の記事を見て
machine.configをいじったが効かない」
という事故が起きやすいのは、この分岐が理由である。
統合モードではmaxWorkerThreads等が無効になる
(後述の変更点)。
補足(現在は、そもそも調整不要なことが多い): 本ページの調整は
.NET Framework の同期処理を前提としている。【同期処理】 1 リクエスト = 1 スレッドを占有 → DB や外部 API を待つ間もスレッドが塞がる → 同時実行数を上げるにはスレッド数を増やすしかない → 本ページのようなチューニングが必要になる 【非同期処理(async/await)】 待っている間はスレッドを解放する → 少ないスレッドで多数のリクエストを捌ける → スレッド数の調整自体が不要になるasync/await を使うことが、
スレッド数を増やすより本質的な解決である。
ASP.NET Core では非同期が前提で、
本ページに相当する設定項目自体がほぼ存在しない。
IIS 6 以前、IIS 7 以降のクラシック・モードでは machine.config で
以下の設定を使用できる。
-
processModel 要素 (ASP.NET 設定スキーマ)
https://learn.microsoft.com/ja-jp/previous-versions/dotnet/netframework-4.0/7w2sway1(v=vs.100) -
ASP.NET アプリケーションから Web サービス要求を行うと、
競合、パフォーマンスの低下、およびデッドロックが発生する
http://support.microsoft.com/kb/821268/ja
.NET 2.0 では自動構成のプロセス モデルを導入したため、
殆どの用途で、KB821268 に推奨される変更は不要とされている。
- ASP.NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0
- Thomas Marquardt's Blog
https://learn.microsoft.com/en-us/archive/blogs/tmarq/asp-net-thread-usage-on-iis-7-5-iis-7-0-and-iis-6-0
状況に応じて machine.configファイル内の
以下のパラメーターを調整する。
- maxWorkerThreads
- minWorkerThreads
- maxIoThreads
- minFreeThreads
- minLocalRequestFreeThreads
- maxconnection
- executionTimeout
-
32 ビットの場合:
%windir%\Microsoft.NET\Framework[.NET バージョン]\CONFIG\machine.config -
64 ビットの場合:
%windir%\Microsoft.NET\Framework64[.NET バージョン]\CONFIG\machine.config
- maxWorkerThreads、minWorkerThreads、maxIoThreads
ワーカ・スレッド、I/O スレッドの最大数を制限する。
<processModel maxWorkerThreads="20" minWorkerThreads="10" maxIoThreads="20">-
注:実際のスレッド数は、上記値に論理 CPU 数が掛けられたもの。
-
注:IIS 7.0 以降のバージョンの統合モードで実行されている場合は機能しない。
-
minFreeThreads および minLocalRequestFreeThreads
維持するフリー スレッドの最小数を制御する。
<httpRuntime minFreeThreads="8" minLocalRequestFreeThreads="8">-
minFreeThreads
スレッド プール内で維持するフリー スレッドの最小数。
必要な数のスレッドが使用できない場合、要求はキューに置かれたままとなる。 -
minLocalRequestFreeThreads
新しいローカル要求を実行するために維持するフリー スレッドの最小数。
注:IIS 7.0 以降のバージョンの統合モードで実行されている場合は機能しない。
- maxconnection
特定の IP アドレスに対して確立できる接続の数を設定する。
<connectionManagement>
<add address="*" maxconnection="2">
<add address="65.53.32.230" maxconnection="12">
</connectionManagement>- executionTimeout
要求の実行時間を制限する。
<httpRuntime executionTimeout="90"/>補足(
maxconnectionは現在も効く/最重要): 上記のうち、
maxconnectionだけは統合モードでも .NET 4.x でも有効であり、
現在も実務でハマる設定である。既定値は「2」(HTTP/1.1 の RFC 由来) → 同一ホストへの同時接続が 2 本に制限される → Web API を大量に呼ぶと、そこがボトルネックになる → [async/await](MS_AsyncAwait) にしても速くならない、という現象<system.net> <connectionManagement> <add address="*" maxconnection="100" /> </connectionManagement> </system.net>// コードからも設定できる(起動時に 1 度だけ) ServicePointManager.DefaultConnectionLimit = 100;.NET Core / .NET では既定値が事実上撤廃されており
(SocketsHttpHandler.MaxConnectionsPerServerの既定がint.MaxValue)、
この問題は起きない。
.NET Framework から移行する動機の一つでもある。なお、
HttpClientを使う場合は
HttpClientを使い回す(IHttpClientFactory)ことも重要である
(毎回newするとソケット枯渇を起こす)。
詳細は HttpClientの類の使い方 を参照。
-
各パラメタの推奨設定値
N:物理 CPU の数ではなく、論理 CPU の数- maxWorkerThreads、maxIoThreads
値を 100 に設定(既定値は 20) - minWorkerThreads
値を 50 に設定(既定では存在しないため追加が必要、既定値は 1) - minLocalRequestFreeThreads
76*N に設定(既定値は 4) - minFreeThreads
値を 88*N に設定(既定値は 8) - maxconnection
値を 12*N に設定(既定値は ?)
- maxWorkerThreads、maxIoThreads
-
競合削減のための推奨スレッド処理設定
第 17 章 「.NET アプリケーション パフォーマンスのチューニング」
https://learn.microsoft.com/en-us/previous-versions/msp-n-p/ff647813(v=pandp.10)
| 構成設定 | 規定値 (.NET 1.1) | 推奨値 |
|---|---|---|
| maxIoThreads | 20 | 100 |
| maxWorkerThreads | 20 | 100 |
| minFreeThreads | 8 | 88*N |
| minLocalRequestFreeThreads | 4 | 76*N |
| maxconnection | 2 | 12*N |
- 設定例
CPU×4 でハイパー スレッディングが有効になっている場合(N=8)。
<system.web>
<processModel maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50"/>
<httpRuntime minFreeThreads="704" minLocalRequestFreeThreads="608"/>
</system.web>
<system.net>
<connectionManagement>
<add address="[ProvideIPHere]" maxconnection="96"/>
</connectionManagement>
</system.net>補足(この推奨値は .NET 1.1 時代のもの): 表の見出しが示す通り、
.NET 1.1の既定値に対する推奨であり、
現在の環境にそのまま適用してはならない。・.NET 2.0 以降は自動構成が入り、既定値自体が変わっている ・IIS 7 統合モードでは maxWorkerThreads / minFreeThreads が無効 ・minFreeThreads を大きくしすぎると、 「空きを確保するために要求をキューに溜める」動作により かえってスループットが落ちる現在の指針は、
- まず計測する(下記のパフォーマンス カウンター)
- 同期処理を非同期化する(async/await)
- それでも足りなければ
maxConcurrentRequestsPerCPUを調整という順序になる。
カウンター 見るもの ASP.NET\Requests Current処理中 + キュー ASP.NET\Requests Queuedキューに溜まっているか ASP.NET Apps\Requests/Secスループット .NET CLR LocksAndThreads\Contention Rateロック競合 Process\Thread Countスレッド数
MaxConcurrentRequestsPerCPU 設定(下記のレジストリ設定)を
使用してください。
IIS 7 以降の統合モード+.NET 3.5 以前では以下のレジストリ設定を使用できる。
- IIS 7 での ASP.NET 2.0 の互換性に影響する変更点
https://learn.microsoft.com/ja-jp/previous-versions/technet-magazine/ff454090(v=msdn.10)
統合モードでは、ASP.NET スレッド設定を使用して要求の同時実行性を制御できない。
- processModel 構成セクションの
- maxWorkerThreads 設定
- system.web/httpRuntime 構成セクションの
- minFreeThreads と minLocalRequestFreeThreads 設定、
は、ASP.NET で使用されるスレッド メカニズムを制御しなくなりました。
補足(なぜ効かなくなったのか): 統合モードでは
ASP.NET が独自のスレッド プールを持たなくなったためである。【クラシック モード】 IIS(w3wp) ──ISAPI──> aspnet_isapi.dll └ ASP.NET 独自のスレッド プール (ここを machine.config で制御していた) 【統合モード】 IIS(w3wp) のパイプラインに ASP.NET が組み込まれる → IIS のスレッド プールをそのまま使う → ASP.NET 側の設定は意味を持たないこれは ASP.NET CoreのWebサーバ で述べた
インプロセス ホスティングの先祖にあたる構造変更である。
「ASP.NET を IIS のパイプラインに溶かし込む」という方向は、
ASP.NET Core のインプロセス ホスティングまで一貫している。
その代わり、ASP.NET は IIS スレッド プールに依存し、
- HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\2.0.50727.0 キー内の
- MaxConcurrentRequestsPerCPU の DWORD 値 (既定値は 12)
を設定することで、同時実行要求の最大数を制御できるようになりました。
この設定はグローバルなので、
- アプリケーション プールや
- アプリケーションごとに
変更することはできません。
IIS 7 以降の統合モード+.NET 3.5 SP1 以降では aspnet.config で
以下の設定を使用できる。
※ Manual 上は、.NET 4 以降になっているが、実際は .NET 3.5 SP1 から採用されている。
- Web 設定スキーマ
https://learn.microsoft.com/ja-jp/previous-versions/dotnet/netframework-4.0/dd560844(v=vs.100)- system.web 要素 (Web 設定)
https://learn.microsoft.com/ja-jp/previous-versions/dotnet/netframework-4.0/dd560839(v=vs.100)- applicationPool 要素 (Web 設定)
https://learn.microsoft.com/ja-jp/previous-versions/dotnet/netframework-4.0/dd560842(v=vs.100)
- applicationPool 要素 (Web 設定)
- system.web 要素 (Web 設定)
ASP.NET アプリケーションが
IIS 7.0 以降のバージョンの統合モードで実行されている場合に、
プロセス全体の動作を管理するために ASP.NET で使用される構成設定を指定します。
- IIS 6 を実行する場合や、
- IIS 7.0 をクラシック モード
- または ISAPI モードで実行する場合は、
これらの設定は無視されます。
- 32 ビットの場合:
%windir%\Microsoft.NET\Framework[.NET バージョン]\aspnet.config - 64 ビットの場合:
%windir%\Microsoft.NET\Framework64[.NET バージョン]\aspnet.config
- applicationPool 要素の属性
-
maxConcurrentRequestsPerCPU
- ASP.NET で許可する CPU あたりの同時要求数を指定する。
- .NET 4 での既定の設定は "5000"
-
maxConcurrentThreadsPerCPU
- 各 CPU のアプリケーション プールで実行できるスレッド数を指定する。
- 既定の設定 0 は、CPU あたりの作成可能なスレッド数を制限しない。
- ただし、作成可能なスレッド数には、CLR のスレッド プールによる制限も適用される。
-
requestQueueLimit
- ASP.NET のキューに配置できる要求の最大数を指定する。
- 複数の ASP.NET アプリケーションを 1 つのアプリケーション プールでホストする場合、
そのアプリケーション プールに対する要求の累積数を制限するために使用する。 - .NET 4 での既定の設定は "5000"
-
既定値
<configuration>
<system.web>
<applicationPool
maxConcurrentRequestsPerCPU="5000"
maxConcurrentThreadsPerCPU="0"
requestQueueLimit="5000" />
</system.web>
</configuration>補足(.NET 4 で既定値が大幅に緩和された): 既定値の変遷が
重要なので補っておく。
.NET 3.5 以前 .NET 4 以降 maxConcurrentRequestsPerCPU12(レジストリ) 5000 想定 同期処理が中心 非同期処理を想定
12から5000への変更は、
「.NET 4 で非同期処理(TAP)が整い、
スレッドを占有しない前提に切り替わった」ことを反映している。このため、.NET 4 以降では通常この値を触る必要が無い。
触るとすれば、
- 同期的にブロックする処理が多く、意図的に絞りたい(過負荷保護)
- スレッド プールの飢餓が起きており、キューを制限したい
といった場合に限られる。
ASP.NET Core での対応物は次の通り。
目的 ASP.NET Core 同時接続数の制限 KestrelServerLimits.MaxConcurrentConnections同時実行の制御 ConcurrencyLimiterミドルウェア / レート制限(.NET 7+)キューの制限 同上( QueueLimit)// .NET 7 以降のレート制限 builder.Services.AddRateLimiter(o => o.AddConcurrencyLimiter("api", opt => { opt.PermitLimit = 100; opt.QueueLimit = 50; }));
ApplicationHost.config にも、machine.configと同様に
processModel タグがあるが、
machine.configの processModel タグとは異なり、
同時実行制御に関する設定は存在しない。
- applicationPool のリサイクリングなどの設定ができる。
- 同時実行制御に関する設定(maxWorkerThreads 等)は存在しない。
%windir%\system32\inetsrv\config\ApplicationHost.config
移行メモ(表記): 原文のパスは全角疑問符(
?)で区切られ、
ファイル名も「ApplcationHost.config」と綴りが誤っていたため、
%windir%\system32\inetsrv\config\ApplicationHost.configに修正した。
- アプリケーション プールのプロセス モデル設定 processModel
https://learn.microsoft.com/en-us/iis/configuration/system.applicationhost/applicationpools/add/processmodel
applicationPool のリサイクリングなどの設定ができる。
<applicationPools>
<add name="DefaultAppPool" autoStart="true" />
<add name="Classic .NET AppPool" managedPipelineMode="Classic" />
<add name="MyAppPool" autoStart="true" managedPipelineMode="Integrated" />
<applicationPoolDefaults>
<processModel identityType="ApplicationPoolIdentity" />
</applicationPoolDefaults>
</applicationPools>補足(性能に効くのはむしろこちら): 同時実行数より、
アプリケーション プールのリサイクル設定の方が
実務では問題になりやすい。
設定 既定 注意点 idleTimeout20 分 アクセスが無いとプロセスが落ち、次回が遅い 定期リサイクル( periodicRestart/time)29 時間 毎日ずれた時刻に再起動する(意図しない断) startModeOnDemand AlwaysRunningで常駐させられるidentityTypeApplicationPoolIdentity DB へ統合認証するなら要検討 **「たまに初回アクセスが極端に遅い」**という症状は、
ほぼidleTimeoutによるプロセス終了が原因である。<add name="MyAppPool" startMode="AlwaysRunning"> <processModel idleTimeout="00:00:00" /> <!-- 無効化 --> <recycling> <periodicRestart time="00:00:00"> <!-- 時間での再起動を無効化 --> <schedule><clear /><add value="03:00:00" /></schedule> <!-- 深夜に固定 --> </periodicRestart> </recycling> </add>併せて Application Initialization(事前ウォームアップ)を
有効にすると、再起動後の初回アクセスも速くできる。
統合モードでは ASP.NET アプリケーション キューが使用されないので、
パフォーマンス カウンター:"ASP.NET Applications\Requests in Application Queue"
の値が常に 0 になる
補足: 統合モードで見るべきカウンターは
ASP.NET\Requests Queued(アプリケーション単位ではなく全体)である。
「キューが 0 だから問題ない」と誤読しないよう注意する。
IIS 7 は Web.config ファイルの ASP.NET 変更通知設定に関係なく、
Web.config ファイルを監視し、これが変更されると、
常に ASP.NET アプリケーションを再起動するため、
system.web/httpRuntime 構成セクションの
- waitChangeNotification
- maxWaitChangeNotification
属性の効果がない。
補足(再起動を引き起こすもの):
web.config以外にも、
アプリケーション ドメインの再起動を引き起こす操作は多い。
操作 再起動 web.configの変更する(本節) bin内の DLL の変更する App_Code/Global.asaxの変更する サブフォルダの削除 する(意外な落とし穴) App_Data内のファイル変更しない 再起動されると、InProc セッションが全消失するため、
「本番でweb.configを 1 行直したらログイン中のユーザーが全部落ちた」
という事故につながる。対策は、
- セッションを StateServer / SQL Server に外す
(ASP.NET Coreの分散キャッシュ の
ASP.NET 版にあたる)- 設定変更をリリース手順に組み込む(本番で直接編集しない)
という運用面の整備になる。
- ASP.NET 構成ファイルの階層と継承
https://learn.microsoft.com/ja-jp/previous-versions/aspnet/ms178685(v=vs.100) - ASP.NET Core でのパフォーマンスのベスト プラクティス
https://learn.microsoft.com/ja-jp/aspnet/core/performance/performance-best-practices - ASP.NET Core のレート制限ミドルウェア
https://learn.microsoft.com/ja-jp/aspnet/core/performance/rate-limit
Tags: 移行, .NET開発, ASP.NET
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。