Asp.netコア2.0に移行したasp.netアプリのパフォーマンスとスケーラビリティの問題をトラブルシューティングしています。私たちのアプリはAzureでアプリサービスとしてホストされており、適度なトラフィックがあると、非常に簡単に転倒してしまいます。
私を困惑させていることの1つは、複数の同時要求がどのように処理されるかです。 ここで読みました から、Kestrelは複数のイベントループを使用してリクエストを処理します。しかし、実際のユーザーコードは.netスレッドプールで処理されます( ここから )。
だから、実験として-新しいasp.netコア2.0 MVCアプリを作成し、かなり厄介なアクションメソッドを追加しました。
[AllowAnonymous]
public ActionResult Wait1()
{
System.Threading.Tasks.Task.Delay(1000).Wait();
return new StatusCodeResult((int)HttpStatusCode.OK);
}
これをAzureにプッシュするときに、たとえば100件のリクエストを同時に送信すると、はずです 100リクエストは軽負荷のように聞こえますか?そして、待機はスレッドプールスレッドで発生しますよね?
だから-私はこれだけをやるとかなり悪い結果が得られます-サンプルは赤で強調表示されています:
うーん、私が期待したものではなく、リクエストごとに約50秒...しかし、リクエストを1秒間隔で配置するように頻度を変更すると、応答時間は問題ありません。同時に30個以上のリクエストをすると、苦しみ始めて、なかなか少ない感じがします。
だから-私は自分の厄介なアクションメソッドがブロックしていることに気づきましたが、スレッドプールスレッドでブロックするので、30以上のものに対処できると思っていました。
これは予期された動作ですか?そうであれば、非同期コードを使用せずにIOにバインドされた作業が行われないことを確認するだけのケースですか?
これは予期された動作ですか?そうであれば、非同期コードを使用せずにIOにバインドされた作業が行われないことを確認するだけのケースですか?
私の経験に基づいて、それは予想通りの動作であるようです。 blog から答えを得ることができます。
ここで、ASP.NetアプリケーションをIIS=で実行しており、Webサーバーに合計4つのCPUがあると仮定します。ある時点で、処理される要求が100あるとします。デフォルトでは、ランタイムは4つのスレッドを作成し、最初の4つの要求を処理するために使用可能になります。500ミリ秒が経過するまで追加のスレッドは追加されないため、他の96個のリクエストはキューで待機する必要があります500ミリ秒が経過すると、新しいスレッドが作成されます。
ご覧のとおり、ワークロードに追いつくには100 * 500ms間隔が必要です。
これが 非同期プログラミング を使用する正当な理由です。非同期プログラミングでは、リクエストの処理中にスレッドがブロックされないため、4つのスレッドがほぼ即座に解放されます。
非同期コードを使用してパフォーマンスを向上させることをお勧めします。
public async Task<ActionResult> Wait1()
{
await Task.Delay(TimeSpan.FromSeconds(15));
return new StatusCodeResult((int)HttpStatusCode.OK);
}
また、別の SOスレッド も見つけました。これを参照してください。