NewRelicを使用して、サーバー側のアプリケーショントレースを提供しています。
一部のアプリケーションでは、メソッドSystem.Web.Mvc.MvcHandler.BeginProcessRequest()
で一貫して約100ミリ秒を費やしていることに気付きました。
これは、カスタムコントローラーコードが呼び出される前に発生します(これは累積的にではなく、個別にログに記録されます)-このメソッドで多くの時間を費やす理由は明らかではありません。
このメソッドでは、MVCはどのようなことを行いますか?これは単にリクエストのキューイングでしょうか?
[編集:] 疑わしい-以下のScalayerの答えは正しかった。セッションの依存関係をすべて削除して最適化し、アプリケーションのスケーラビリティと安定性が大幅に向上した
あなたが見ているかもしれないものは、一般に.NETのスレッドアジリティと呼ばれます。
トピックラベル(つまり、System.Web.HttpApplication.BeginRequest()
のアプリケーションコード)の下にある結果に関する限り、スレッドアジリティの問題です。ほとんどの場合、ここで表示される時間は必ずしもコードが実行されているわけではなく、スレッドがリーダー/ライターロックから解放されるのを待っているWebコンテキストです。
Application_BeginRequest()
"pause"は、ASP.NET Webスタックでかなり普及しているものです。一般に、BeginRequestで長いロード時間が表示される場合、特にIOおよびセッションベースの操作を処理する場合は、ASP.NETスレッドの敏/性および/またはスレッドロックを処理します。これは、.netがスレッドの並行性を確保する方法です。
通常、BeginRequestとPreRequestHandlerExecuteの間に時間差が生じます。アプリケーションがセッションにいくつかのことを書き込んでいる場合、ASP.NETはHttpContext.Current.Session
にリーダー/ライターロックを発行します。
これがあなたが直面しているかもしれない問題であるかどうかを確認する良い方法は、敏ID性が問題であるかどうかを確認するためにスレッドIDをチェックすることです-IDは与えられたリクエストに対して異なります。
例えば。デバッグ中に、おそらく次をGlobal.asax.cs
に追加できます。
protected void Application_BeginRequest(Object sender, EventArgs e) {
Debug.WriteLine("BeginRequest_" + Thread.CurrentThread.ManagedThreadId.ToString());
}
デバッグ出力ウィンドウを開きます(Visual Studioの[表示] >> [出力]から、[出力を表示]ドロップダウンから[デバッグ]を選択します)。
デバッグ中に、長い間見たページにヒットします。次に、出力ログを表示します-複数のIDが表示される場合、これに悩まされている可能性があります。
これが、遅延が時々見られるが他の時間には見られない理由です。アプリケーションコードがセッションを少し異なる方法で使用している場合や、セッションまたはIO操作がページごとに上下する場合があります.
この場合、サイトまたは各ページでセッションがどのように使用されているかに応じて、速度を上げるためにできることがいくつかあります。
セッションを変更しないページの場合:
<% @Page EnableSessionState="ReadOnly" %>
セッション状態を使用しないページの場合:
<% @Page EnableSessionState="False" %>
アプリがセッション(web.config)を使用しない場合:
<configuration>
<system.web>
<sessionState mode="Off" />
</system.web>
</configuration>
それでは、次の例を見てみましょう。
ユーザーはページを読み込み、最初の要求が完了する前に別のページに移動することを決定します。ASP.NETの読み込みはセッションロックを強制し、新しいページ要求の読み込みは最初のページ要求が完了するまで待機します。 ASP.NET MVCでは、各アクションが同期のためにユーザーセッションをロックします。同じ問題を引き起こしています。
ロックが解放されるまでにかかった時間はすべて、ユーザーがセッションを放棄し、戻ってくるスレッドがもはや存在しないユーザーを探しているものは言うまでもなく、新しい遺物によって報告されます。
ちなみに、UpdatePanelコントロールは同じ動作を引き起こします-
http://msdn.Microsoft.com/en-us/magazine/cc163413.aspx
できること:
このロックの問題は、MicrosoftがSessionStateUtilityクラスを持っている理由の1つです-
http://msdn.Microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx
このRedis実装で見られるように、この問題に直面した場合、デフォルトの動作をオーバーライドできるように: https://github.com/angieslist/AL-Redis
.netベースのWebサイトで使用されるデフォルトの状態プロバイダーには多くのオプションがあります。ただし、一般にこのトランザクション時間は、スレッドがロックされ、サーバーへの要求が完了するのを待っていることを示しています。
特定のコントローラーが単一ユーザーからのリクエストを並行して処理できるようにしたい場合は、バージョン3以降MVCで導入されたSessionStateという名前の属性を使用できます。 SessionStateBehaviorのReady-onlyオプションを使用すると、セッションデータに基づいて実装したセキュリティチェックに合格できます。
_[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public class ParallelController : Controller
{
...
}
_
また、いくつかの長時間実行アクションを実行しようとすると、System.Web.Mvc.MvcHandler.BeginProcessRequest()
に遅延があり、NewRelic
でそれを確認しました。この属性により問題が解決され、このコントローラーのアクションを並行して処理できるようになりました。
セッションの使用が非常に少ないアプリでも同じ問題が発生しました。受け入れられた答えを考慮し、診断目的で一時的にSessionStateを完全に削除した後でも、この「メソッド」のパフォーマンスに重大な問題がありました
このスレッド のtodd_saylorのコメントに基づいて、私は自分のサイトで多くの調査を行い、BeginProcessRequest
がNew Relicのキャッチオールとして役立つことがわかった異なるコード領域。 Red GateのANTs Performance Profilerを使用してローカルマシンでコードをプロファイリングすることで、この分野の時間を大幅に短縮することができました。
私のローカルプロファイリングはいくつかのことを明らかにしました:
Project().To<>()
とLinqのSql Serverプロバイダーの間のどこかで、プロジェクションの動的コンパイルとJITが要求時間の50%を占めていることがわかりました。これをCompiledQuerysに置き換えると、もう1つの大きな凹みができました。これが他の誰かに役立つことを願っています!
これを読んでいる人にIIS説明されていない高いCPU使用率については、私が開いたNewRelicサポートフォーラムからこのスレッドを見てください。
私は、問題の根本原因が彼らのエージェントであることに気づくまで、この問題に一週間以上取り組んできました。
そのため、最初に試すことをお勧めするのは、より複雑な実験に飛び込む前に、.NETエージェントを削除して変更があるかどうかを確認することです。
私は問題に取り組んでいるときに最初にここに来たので、この特定の質問にこの答えを投稿し、スレッドの敏g性は正しくない長いコースに私を設定しました...(それ自体は非常に興味深いものですが)。