IIS7 以降で利用できる 統合パイプラインモードでは、ASP.NET が扱うことができる最大要求数は、requestQueueLimit(デフォルトで 5,000)で決まるという話を書きます。
この件に関して自分が参考にした Microsoft のサイトの記事は以下のとおりです。これらをベースに話をします。
-
<applicationPool> 要素 (Web 設定)
-
ASP.NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0
-
IIS 7 での ASP.NET 2.0 の互換性に影響する変更点
なお、統合パイプラインモードかクラッシックモードかによって話が違ってきます。ASP.NET のバージョンによっても話が違ってきます。以下の話は統合パイプラインモードで ASP.NET 2.0 以降のバージョンの場合ですのでご注意ください。
(クラシックモードや IIS6 の場合は上の参考記事 2 を見てください。手抜きですみません)
上の参考記事の 1 に書いてあるとおり、統合パイプラインモードで ASP.NET 3.5 以降の場合、aspnet.config ファイルでの applicationPool 要素の設定が有効になります。
applicationPool 要素は以下の 3 つの属性を持っています。それぞれの詳しい説明は上の参考記事 1 を見てください。以下の ( ) 内の数字はデフォルト値です。
-
maxConcurrentRequestsPerCPU (ASP.NET 3.5: 12, ASP.NET 4: 5000)
-
maxConcurrentThreadsPerCPU (0)
-
requestQueueLimit (5000)
ASP.NET 2.0 では applicationPool 要素は使用できませんが、代わりに、レジストリで MaxConcurrentRequestsPerCPU(デフォルトで 12)と、web.config で processModel 要素 の requestQueueLimit 属性(デフォルトで 5,000)の設定が有効になります。
maxConcurrentRequestsPerCPU については、上の参考記事 1 によると、この設定値を超えると ASP.NET によって制御される要求調整がかかるということです。(ASP.NET 4 のデフォルト値 5,000 では実質的に要求調整はかからないということらしいです)
要求調整とは、上の参考記事 2 にある "the CLR Threadpool is still controlled by the processModel configuration settings (autoConfig, maxWorkerThreads, maxIoThreads, minWorkerThreads, and minIoThreads). And autoConfig is still enabled, but its modifications to httpRuntime/minFreeThreads and httpRuntime/minLocalRequestFreeThreads do nothing, since the application-level queues do not exist." のことだと思われます。
ちなみに、maxConcurrentRequestsPerCPU を 0 に設定すると、IIS I/O スレッドから CLR スレッドへの切り替えは行われず、そのまま IIS I/O スレッドで処置されるそうです。
maxConcurrentRequestsPerCPU の設定値を超えると、上で言う要求調整がかかると思いますが、要求を受けるたび CLR スレッドプールから空いているスレッドを借り出して、そのスレッドで要求を処理するという動作には変わりないはずです。ただし、CLR スレッドプールにあるスレッドの数(要求調整で変わる?)には制限があるので、空いているスレッドがなくなると要求はキューに溜まるということになります。
従って、ASP.NET が扱うことができる最大要求数は、最終的に requestQueueLimit の設定値(デフォルトで 5,000)で決まるということになります。上の参考記事の 2 にも以下のように書いてあります。
"As a final remark, please note that the processModel/requestQueueLimit configuration limits the maximum number of requests in the ASP.NET system for IIS 6.0, IIS 7.0, and IIS 7.5. This number is exposed by the "ASP.NET/Requests Current" performance counter, and when it exceeds the limit (default is 5000) we reject requests with a 503 status (Server Too Busy)."
(注: 上で "processModel/requestQueueLimit" と言っていますが、ASP.NET 3.5 以降であれば applicationPool 要素の requestQueueLimit の設定の方が優先されます)
"in the ASP.NET system" の system というところに注意してください。system = アプリケーションプールらしいです。根拠は、上の参考記事 1 の requestQueueLimit 属性の説明に "アプリケーションプール内のアプリケーションに対する要求の累積数は、この設定によって制限されます" と書いてあるところです。
上の参考記事の 2 によると、一般的にはデフォルトのままでいいそうです。ただし、処理に時間がかかるアプリケーション(例えば、他のサイトの Web サービスとの通信に 100 ms かかるような)で、多くの同時要求を処理する場合(多いというのは 12 ~ 5,000 per CPU とのこと)は、以下のような設定の変更した方がいいそうです。
-
ASP.NET 2.0 では、レジストリの設定を変更して MaxConcurrentRequestsPerCPU を 5000 にする。
-
ASP.NET 3.5 では、aspnet.config ファイルで applicationPool 要素の maxConcurrentRequestsPerCPU 属性を 5000 に設定する。
レジストリで設定しても良いが、aspnet.config ファイルと両方に設定した場合、aspnet.config ファイルの設定が優先されるそうです。
-
ASP.NET 4 以降では、maxConcurrentRequestsPerCPU はデフォルトで 5000 なので何もする必要はない。
-
HTTP.sys キュー(デフォルトで 1,000)を増やす。
これは requestQueueLimit で設定する CLR スレッドプールのキューの制限ではなく、IIS I/O スレッドのキューです。IIS Manager を開いて、Application Pool の詳細設定で表示される[キューの長さ]で設定できます。アプリケーションを x64 で動かしていて、2GB 以上のメモリがある場合は 5000 でいいそうです。
-
他のサイトの Web サービスなどと HTTP で通信している場合は、そのサービスへの最大接続数を connectionManagement 要素 の maxconnection を調整して増やす。
processModel/autoCongfig によって 12 per CPU に設定されるそうです。調整の仕方は上の参考記事 2 を参照してください。
-
バースト的に同時要求が増えることがある場合は、アプリケーションを非同期にする。
その理由は、CLR スレッドプールのスレッドの数を急には増やすことができないからだそうです。「非同期」の意味は MSDN の記事「ASP.NET の非同期/待機の概要」を見てください。
maxConcurrentRequestsPerCPU 等の値は、既存の aspnet.config には何故か applicationPool 要素は設定されていないのですが、ASP.NET 4 以降であれば以下のようにして取得できます。上の画像はそれらの値を表示したものです。(applicationPool 要素の requestQueueLimit 要素の設定値の取得方法は分かりませんでした)
int maxConcurrentRequestsPerCPU =
HostingEnvironment.MaxConcurrentRequestsPerCPU;
int maxConcurrentThreadsPerCPU =
HostingEnvironment.MaxConcurrentThreadsPerCPU;
int requestQueueLimit =
((ProcessModelSection)WebConfigurationManager.
GetSection("system.web/processModel")).
RequestQueueLimit;