Skip to content

MS_ASPNETConfig

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

ASP.NET config

概要

同時実行性を向上させるためのパラメタについて纏める。

サマリすると以下の様になる。

  • 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.configprocessModel
IIS 6 以前 2.0+ 自動構成(通常は変更不要)
IIS 7+ クラシック 〜4 以前 レジストリMaxConcurrentRequestsPerCPU
IIS 7+ 統合 〜3.5 レジストリ
IIS 7+ 統合 3.5 SP1 以降 aspnet.configapplicationPool

「昔の記事を見て machine.config をいじったが効かない」
という事故が起きやすいのは、この分岐が理由である。
統合モードでは maxWorkerThreads 等が無効になる
(後述の変更点)。

補足(現在は、そもそも調整不要なことが多い): 本ページの調整は
.NET Framework の同期処理を前提としている。

【同期処理】
   1 リクエスト = 1 スレッドを占有
     → DB や外部 API を待つ間もスレッドが塞がる
     → 同時実行数を上げるにはスレッド数を増やすしかない
     → 本ページのようなチューニングが必要になる

【非同期処理(async/await)】
   待っている間はスレッドを解放する
     → 少ないスレッドで多数のリクエストを捌ける
     → スレッド数の調整自体が不要になる

async/await を使うことが、
スレッド数を増やすより本質的な解決である。
ASP.NET Core では非同期が前提で、
本ページに相当する設定項目自体がほぼ存在しない。

machine.config

IIS 6 以前、IIS 7 以降のクラシック・モードでは machine.config で
以下の設定を使用できる。

IIS 6 以前、IIS 7 以降のクラシック・モード + .NET 2.0

.NET 2.0 では自動構成のプロセス モデルを導入したため、
殆どの用途で、KB821268 に推奨される変更は不要とされている。

IIS 6 以前、IIS 7 以降のクラシック・モード + .NET 1.1

状況に応じて 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 に設定(既定値は ?)
  • 競合削減のための推奨スレッド処理設定

第 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 を大きくしすぎると、
  「空きを確保するために要求をキューに溜める」動作により
  かえってスループットが落ちる

現在の指針は、

  1. まず計測する(下記のパフォーマンス カウンター)
  2. 同期処理を非同期化するasync/await
  3. それでも足りなければ 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 4 以前

MaxConcurrentRequestsPerCPU 設定(下記のレジストリ設定)を
使用してください。

IIS 7 以降の統合モード+.NET 3.5 以前

IIS 7 以降の統合モード+.NET 3.5 以前では以下のレジストリ設定を使用できる。

変更点

統合モードでは、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)

を設定することで、同時実行要求の最大数を制御できるようになりました。

この設定はグローバルなので、

  • アプリケーション プールや
  • アプリケーションごとに

変更することはできません。

aspnet.config

IIS 7 以降の統合モード+.NET 3.5 SP1 以降

IIS 7 以降の統合モード+.NET 3.5 SP1 以降では aspnet.config で
以下の設定を使用できる。
※ Manual 上は、.NET 4 以降になっているが、実際は .NET 3.5 SP1 から採用されている。

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 以降
maxConcurrentRequestsPerCPU 12(レジストリ) 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

ApplicationHost.config にも、machine.configと同様に
processModel タグがあるが、
machine.configの processModel タグとは異なり、
同時実行制御に関する設定は存在しない。

  • applicationPool のリサイクリングなどの設定ができる。
  • 同時実行制御に関する設定(maxWorkerThreads 等)は存在しない。

ファイルの場所

%windir%\system32\inetsrv\config\ApplicationHost.config

移行メモ(表記): 原文のパスは全角疑問符(?)で区切られ、
ファイル名も「ApplcationHost.config」と綴りが誤っていたため、
%windir%\system32\inetsrv\config\ApplicationHost.config に修正した。

設定可能な値

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>

補足(性能に効くのはむしろこちら): 同時実行数より、
アプリケーション プールのリサイクル設定の方が
実務では問題になりやすい。

設定 既定 注意点
idleTimeout 20 分 アクセスが無いとプロセスが落ち、次回が遅い
定期リサイクル(periodicRestart/time 29 時間 毎日ずれた時刻に再起動する(意図しない断)
startMode OnDemand AlwaysRunning で常駐させられる
identityType ApplicationPoolIdentity 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(事前ウォームアップ)を
有効にすると、再起動後の初回アクセスも速くできる。

補足

補足1 (統合モード)

統合モードでは ASP.NET アプリケーション キューが使用されないので、

パフォーマンス カウンター:"ASP.NET Applications\Requests in Application Queue"

の値が常に 0 になる

補足: 統合モードで見るべきカウンターは
ASP.NET\Requests Queued(アプリケーション単位ではなく全体)である。
「キューが 0 だから問題ない」と誤読しないよう注意する。

補足2 (IIS 7)

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 版にあたる)
  • 設定変更をリリース手順に組み込む(本番で直接編集しない)

という運用面の整備になる。

参考

Microsoft Learn


Tags: 移行, .NET開発, ASP.NET

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally