編集 私の質問が十分に明確に述べられていないことに気づき、大幅に編集しました。
これは少し自由回答形式の質問ですので、事前にお詫び申し上げます。
簡単に言えば、IIS スタイルの非同期要求処理を Azure ワーカー ロールに実装したいと考えています。
それは非常に単純かもしれませんし、非常に難しいかもしれません - 私は研究する場所へのポインタを探しています.
今回の実装では Azure ワーカーとサービス バス キューを使用しますが、一般的な原則は、ワーカー プロセスが着信要求をリッスンして処理するシナリオすべてに適用できます。
IIS の機能
IIS には、固定サイズのスレッドプールがあります。すべてのリクエストを同期的に処理する場合、並行して処理できるリクエストの最大数 == maxthreads. ただし、リクエストを処理するために低速の外部 I/O を実行する必要がある場合、これは非常に非効率的です。これは、サーバーがアイドル状態になる可能性があるため、外部 I/O が完了するのを待ってすべてのスレッドが拘束される可能性があるためです。
MSDNから:
Web サーバーでは、.NET Framework は、ASP.NET 要求の処理に使用されるスレッドのプールを維持します。リクエストが到着すると、そのリクエストを処理するためにプールからスレッドがディスパッチされます。要求が同期的に処理される場合、要求が処理されている間、要求を処理するスレッドはブロックされ、そのスレッドは別の要求を処理できません。
スレッド プールは、多くのブロックされたスレッドを収容するのに十分な大きさにすることができるため、これは問題にならない可能性があります。ただし、スレッド プール内のスレッドの数は制限されています。複数の同時実行時間の長い要求を処理する大規模なアプリケーションでは、使用可能なすべてのスレッドがブロックされる可能性があります。この状態は、スレッド スターベーションと呼ばれます。この条件に達すると、Web サーバーは要求をキューに入れます。要求キューがいっぱいになると、Web サーバーは HTTP 503 ステータス (Server Too Busy) で要求を拒否します。
この問題を克服するために、IIS には、要求を非同期で処理できる巧妙なロジックがあります。
非同期アクションが呼び出されると、次の手順が発生します。
Web サーバーは、スレッド プール (ワーカー スレッド) からスレッドを取得し、着信要求を処理するようにスケジュールします。このワーカー スレッドは、非同期操作を開始します。
ワーカー スレッドは、別の Web 要求を処理するためにスレッド プールに返されます。
非同期操作が完了すると、ASP.NET に通知されます。
Web サーバーは、スレッド プール (非同期操作を開始したスレッドとは別のスレッドである可能性があります) からワーカー スレッドを取得し、応答のレンダリングを含め、残りの要求を処理します。
ここで重要な点は、非同期リクエストが戻るときです。戻りアクションは、最初の着信リクエストを処理するスレッドの同じプールの 1 つで実行されるようにスケジュールされています。これは、システムが同時に実行する作業の量を制限していることを意味し、これを再現したいと考えています。
私がしたいこと
Azure Service Bus キューおよび場合によっては TCP ソケットで着信作業要求をリッスンする Worker ロールを作成したいと考えています。IIS のように、スレッドプールの最大サイズを設定し、ワーカーが並行して実行する実際の作業量を制限したいと考えています。ワーカーが既存のリクエストを処理するのに忙しい場合 (新しい受信リクエストであろうと、以前の非同期呼び出しからのコールバックであろうと)、いくつかのスレッドが解放されるまで、新しい受信リクエストを取得したくありません。
同時に開始するジョブの数を制限することは問題ではありません。これは簡単に制御できます。実際に同時に作業している数を制限しています。
100 スレッドのスレッドプールを想定しましょう。
電子メールを送信するための 100 の要求が届き、各電子メールが SMTP サーバーに送信されるのに 5 秒かかります。サーバーが同時に 100 個のリクエストのみを処理するように制限すると、CPU が完全にアイドル状態になるまで、サーバーは 5 秒間他の操作を行うことができなくなります。したがって、「リクエスト処理時間」の 99% が外部 I/O の待機に費やされ、サーバーがまだ非常に静かであるため、同時に 1,000 通または 10,000 通のメールを送信し始めてもかまいません。したがって、着信リクエストを制限なしで受け入れ続けることで対処できる特定のシナリオ (または、非同期呼び出しを開始するまでリクエストの開始を制限するだけです。BeginSend が呼び出されるとすぐに、戻って開始します)別のリクエストを処理します)。
代わりに、データベースにアクセスしてデータを読み取り、重い計算を行ってからデータベースに書き戻すタイプのリクエストがあるとします。非同期にする必要がある 2 つのデータベース リクエストがありますが、リクエスト処理時間の 90% がワーカーに費やされます。したがって、上記と同じロジックに従って非同期呼び出しを開始し、スレッドを続行するために必要なことは何でもリターンに任せると、サーバーが非常に過負荷になることになります。
どういうわけか、IIS が行うことは、非同期呼び出しが返されたときに同じ固定サイズのスレッド プールが使用されるようにすることです。これは、大量の非同期呼び出しを開始し、それらが戻ってスレッドの使用を開始した場合、IIS はそれらの戻りが完了するまで新しい要求を受け入れないことを意味します。特に複数の負荷分散されたサーバーとサーバーが作業を選択するキューシステムがある場合は、サーバーに適切な負荷がかかるため、これは完璧です。
私は、これを行うのは非常に簡単かもしれないという卑劣な疑いを持っています.私が欠けている基本的なものがあります. あるいは、めちゃくちゃ難しいのかもしれません。