最近、ASP.NET MVC3 コントローラーの 1 つにいくつかの (かなり些細な) 変更を加え、アクションの 1 つを非同期アクションに変更しました。基本的に、次のようなコードを取りました。
public ActionResult MyAction(BindingObject params){
// use HttpWebRequest to call an external API and process the results
}
そして、それを次のようなコードに変換しました。
private delegate ActionResult DoMyAction(BindingObject params);
public void MyActionAsync(BindingObject params){
AsyncManager.OutstandingOperations.Increment();
var doMyAction = new DoMyAction(MyAction);
doMyAction.BeginInvoke(params, MyActionCallback, doMyAction);
}
private void MyActionCallback(IAsyncResult ar){
var doMyAction = ar.AsyncState as DoMyAction;
AsyncManager.Parameters["result"] = doMyAction != null ? doMyAction.EndInvoke(ar) : null;
AsyncManager.OutstandingOperations.Decrement();
}
public ActionResult MyActionCompleted(ActionResult result){
return result;
}
private ActionResult MyAction(BindingObject params){
// use HttpWebRequest to call an external API and process the results
}
MyAction を呼び出してローカルでテストすると、期待どおりに各メソッドのブレークポイントが起動し、最終的に期待される結果が返されます。
HttpWebRequest が外部 API を呼び出すのを待ってワーカー スレッドが消費されず、最悪の場合、まったく効果がないため、この変更により高負荷時のパフォーマンスが向上すると予想されます。
この変更をプッシュする前は、サーバーの CPU 使用率は平均 30% 前後で、W3SVC_W3WP Active Requests perfmon 統計は 10 ~ 15 前後で推移していました。サーバーは Win Server 2008 R2 で、MVC サイトは 1 秒あたり約 50 の要求を取得します。
この変更をプッシュすると、CPU は一定の 90 ~ 100% の使用率まで上昇し、W3SVC_W3WP Active Requests カウンターは、最大値の 5000 に達してそこに留まるまでゆっくりと増加します。Web サイトが完全に応答しなくなります (タイムアウトするか、「サービスを利用できません」というエラーが発生します)。
私の仮定は、AsyncController を正しく実装していないか、必要な追加の構成が欠落しているか、AsyncController の使用目的を誤解しているだけです。いずれにせよ、私の質問は、なぜこれが起こっているのですか?