ASP.NET アプリケーションから Web サービスを呼び出すときのパフォーマンスの問題

この記事では、Microsoft ASP.NET アプリケーションから Web サービスを呼び出すときに発生するパフォーマンスの問題を解決するためのヘルプを提供します。

元の製品バージョン: ASP.NET
元の KB 番号: 821268

現象

ASP.NET アプリケーションから Web サービスを呼び出すと、競合、パフォーマンスの低下、デッドロックが発生する可能性があります。 クライアントは、要求が応答を停止したり、実行に時間がかかることを報告する場合があります。 デッドロックが疑われる場合は、ワーカー プロセスがリサイクルされる可能性があります。

HttpWebRequest.GetResponse メソッドを呼び出すと、次の例外エラー メッセージが表示されることがあります。

"System.InvalidOperationException: ThreadPool オブジェクトに、操作を完了するのに十分な空きスレッドができませんでした。"

ブラウザーで次の例外エラー メッセージが表示される場合もあります。

"HttpException (0x80004005): 要求がタイムアウトしました。"

Note

この記事は、 HttpWebRequest 要求を直接行うアプリケーションにも適用されます。

原因

この問題は、ASP.NET 呼び出しが要求の実行に使用できるワーカー スレッドと完了ポート スレッドの数が制限されているために発生する可能性があります。

通常、Web サービスの呼び出しでは、1 つのワーカー スレッドを使用して要求を送信するコードを実行し、1 つの完了ポート スレッドが Web サービスからコールバックを受信します。 ただし、要求がリダイレクトされるか、認証が必要な場合、呼び出しでは 2 つのワーカー スレッドと 2 つの完了ポート スレッドを使用できます。 そのため、複数の Web サービス呼び出しが同時に発生したときに、マネージド ThreadPool を使い果たすことができます。

たとえば、 ThreadPool が 10 個のワーカー スレッドに制限されており、10 個のワーカー スレッドすべてが現在、コールバックの実行を待機しているコードを実行しているとします。 ThreadPoolにキューに登録されている作業項目は、スレッドが使用可能になるまでブロックされるため、コールバックを実行することはできません。

競合の原因として考えられるもう 1 つは、System.Net名前空間が接続数を制限するために使用するmaxconnection パラメーターです。 通常、この制限は想定どおりに機能します。 ただし、多くのアプリケーションが同時に 1 つの IP アドレスに対して多数の要求を行おうとする場合、スレッドは使用可能な接続を待機する必要があります。

解決方法

これらの問題を解決するには、 Machine.config ファイル内の次のパラメーターを状況に最適に調整します。

  • maxWorkerThreads
  • minWorkerThreads
  • maxIoThreads
  • minFreeThreads
  • minLocalRequestFreeThreads
  • maxconnection
  • executionTimeout

これらの問題を正常に解決するには、次のアクションを実行します。

  • 同時に実行できる ASP.NET 要求の数を CPU あたり約 12 に制限します。
  • Web サービスコールバックが ThreadPool内のスレッドを自由に使用することを許可します。
  • maxconnections パラメーターの適切な値を選択します。 選択内容は、使用される IP アドレスと AppDomain の数に基づいて行います。

Note

ASP.NET 要求の数を CPU あたり 12 個に制限することをお勧めします。 ただし、この制限はほとんどのアプリケーションに適しています。

MaxWorkerThreads と maxIoThreads

ASP.NET では、次の 2 つの構成設定を使用して、使用されるワーカー スレッドと完了スレッドの最大数を制限します。

<processModel maxWorkerThreads="20" maxIoThreads="20">

maxWorkerThreads パラメーターと maxIoThreads パラメーターには、CPU の数が暗黙的に乗算されます。 たとえば、プロセッサが 2 つある場合、ワーカー スレッドの最大数は 2 * maxWorkerThreadsです。

MinFreeThreads と minLocalRequestFreeThreads

ASP.NET には、リモート要求またはローカル要求を開始するために使用できるワーカー スレッドと完了ポート スレッドの数を決定する次の構成設定も含まれています。

<httpRuntime minFreeThreads="8" minLocalRequestFreeThreads="8">

十分なスレッドが使用可能でない場合、要求は、要求を行うのに十分なスレッドが解放されるまでキューに入れられます。 そのため、ASP.NET は、次の数を超える要求を同時に実行しません。

(maxWorkerThreads * CPU の数) - minFreeThreads

Note

minFreeThreads パラメーターと minLocalRequestFreeThreads パラメーターには、CPU の数が暗黙的に乗算されません。

MinWorkerThreads

ASP.NET には、リモート要求を処理するためにすぐに使用できるワーカー スレッドの数を決定する次の構成設定も含まれています。

<processModel minWorkerThreads="1">

この設定によって制御されるスレッドは、共通言語ランタイム (CLR) の既定のスレッド チューニング機能から作成されたワーカー スレッドよりもはるかに高速な速度で作成できます。

この設定を使用すると、バックエンド サーバーの速度低下、クライアント 側からの要求の急激な急増、またはキュー内の要求の数が急激に増加するなどの理由で、ASP.NET 要求キューに突然いっぱいになる可能性がある要求に対して、ASP.NET を処理できます。

minWorkerThreads パラメーターの既定値は 1 です。 minWorkerThreads パラメーターの値を次の値に設定することをお勧めします。

minWorkerThreads = maxWorkerThreads / 2

既定では、 minWorkerThreads パラメーターは、 Web.config ファイルまたは Machine.config ファイルには存在しません。 この設定には、CPU の数が暗黙的に乗算されます。

Maxconnection

maxconnection パラメーターは、特定の IP アドレスに対して実行できる接続の数を決定します。 パラメーターは次のように表示されます。

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://65.53.32.230" maxconnection="12">
</connectionManagement>

アプリケーションのコードが IP アドレスではなくホスト名でアプリケーションを参照する場合、パラメーターは次のように表示されます。

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://hostname" maxconnection="12">
</connectionManagement>

最後に、アプリケーションが 80 以外のポートでホストされている場合、パラメーターには、次のような標準以外のポートを URL に含める必要があります。

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://hostname:8080" maxconnection="12">
</connectionManagement>

この記事で既に説明したパラメーターの設定はすべてプロセス レベルです。 ただし、 maxconnection パラメーターの設定は AppDomain レベルに適用されます。 既定では、この設定は AppDomain レベルに適用されるため、プロセス内の各 AppDomain から特定の IP アドレスへの最大 2 つの接続を作成できます。

ExecutionTimeout

ASP.NET では、次の構成設定を使用して、要求の実行時間を制限します。

<httpRuntime executionTimeout="90"/>

Server.ScriptTimeout プロパティを使用して、この制限を設定することもできます。

Note

executionTimeout パラメーターの値を大きくすると、processModel responseDeadlockIntervalパラメーターの設定を変更しなければならない場合もあります。

推奨事項

このセクションで推奨される設定は、すべてのアプリケーションで機能しない場合があります。 ただし、次の追加情報は、適切な調整を行うのに役立つ場合があります。

各 ASPX ページから 1 つの IP アドレスに対して 1 つの Web サービス呼び出しを行う場合は、次の構成設定を使用することをお勧めします。

  • maxWorkerThreads パラメーターと maxIoThreads パラメーターの値を 100 に設定します。
  • maxconnection パラメーターの値を 12*N に設定します (ここで、N は CPU の数です)。
  • minFreeThreads パラメーターの値を 88*N に設定し、minLocalRequestFreeThreads パラメーターを 76*N に設定します。
  • minWorkerThreadsの値を 50 に設定します。 minWorkerThreadsは既定で構成ファイルに含まれていない点に注意してください。 追加する必要があります。

これらの推奨事項の一部には、サーバー上の CPU の数を含む単純な数式が含まれます。 数式内の CPU の数を表す変数は、 Nです。

これらの設定では、ハイパースレッディングが有効になっている場合は、物理 CPU の数ではなく論理 CPU の数を使用する必要があります。 たとえば、ハイパースレッディングが有効な 4 プロセッサ サーバーがある場合、数式の N の値は 4 ではなく 8 になります。

Note

この構成を使用すると、100 から 88=12 であるため、CPU ごとに最大 12 個の ASP.NET 要求を同時に実行できます。 そのため、少なくとも 88*N ワーカー スレッドと 88*N 完了ポート スレッドは、他の用途 (Web サービス コールバックなど) で使用できます。

たとえば、4 つのプロセッサとハイパースレッディングが有効になっているサーバーがあるとします。 これらの数式に基づいて、この記事で説明する構成設定に次の値を使用します。

<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>

また、この構成を使用すると、各 AppDomain の IP アドレスごとに CPU あたり 12 個の接続を使用できます。 そのため、次のシナリオでは、要求が接続を待機していて、 ThreadPool が使い果たされていない場合に、競合はほとんど発生しません。

  • Web は 1 つのアプリケーション (AppDomain) のみをホストします。
  • ASPX ページの各要求は、1 つの Web サービス要求を行います。
  • すべての要求は同じ IP アドレスに対して行われます。

ただし、この構成を使用する場合、次のいずれかのシナリオで使用される接続が多すぎる可能性があります。

  • 要求は複数の IP アドレスに対して行われます。
  • 要求はリダイレクトされます (302 状態コード)。
  • 要求には認証が必要です。
  • 要求は、複数の AppDomain から行われます。

これらのシナリオでは、 maxconnection パラメーターには小さい値を使用し、 minFreeThreads パラメーターと minLocalRequestFreeThreads パラメーターには大きい値を使用することをお勧めします。

詳細

詳細については、「 パフォーマンスの ASP.NET を調整する」を参照してください。

ASP.NET と共に IIS でパフォーマンスと競合が低い場合は、次の Microsoft ブログを参照してください。