本文介绍了在 BeginProcessRequest() 中会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用 NewRelic 来提供服务器端应用程序跟踪.

我们注意到,我们的一些应用程序始终在 System.Web.Mvc.MvcHandler.BeginProcessRequest() 方法中花费大约 100 毫秒.

这发生在调用任何自定义控制器代码之前(单独记录,而不是累积记录) - 不清楚为什么会在这种方法上花费这么多时间.

MVC 会在这个方法中做什么?这可能只是请求排队吗?

正如所怀疑的那样 - 下面 Scalayer 的回答是准确的.我们删除了 &优化了我们所有的会话依赖项,并看到了应用程序可扩展性的大幅增加和稳定性

解决方案

您可能看到的通常称为 .NET 中的线程敏捷性.

就主题标签下的结果(即 System.Web.HttpApplication.BeginRequest() 中的应用程序代码)而言,您可能看到的是线程敏捷性问题;在大多数情况下,您在此处看到的时间不一定是正在执行的代码,而是等待线程从读写锁释放回它的 Web 上下文.

Application_BeginRequest()暂停"在 ASP.NET 网络堆栈中非常普遍.通常,当您在 BeginRequest 中看到较长的加载时间时,您正在处理 ASP.NET 线程敏捷性和/或线程锁 - 特别是在处理 IO 和基于会话的操作时.并不是说这是一件坏事,这就是 .net 确保您的线程保持并发的方式.

时间间隔一般出现在BeginRequest 和PreRequestHandlerExecute 之间.如果应用程序正在向会话写入多个内容,则 ASP.NET 将在 HttpContext.Current.Session 上发出读写锁.

查看这是否是您可能面临的问题的一个好方法是检查线程 ID 以查看是否存在敏捷性问题 - 给定请求的 ID 会有所不同.

例如.在调试时,也许您可​​以将以下内容添加到您的 Global.asax.cs 中:

protected void Application_BeginRequest(Object sender, EventArgs e) {Debug.WriteLine("BeginRequest_" + Thread.CurrentThread.ManagedThreadId.ToString());}

打开调试输出窗口(从 Visual Studio:查看 >> 输出,然后从显示输出"下拉列表中选择调试").

在调试的时候,打一个你看过很久的页面.然后查看输出日志 - 如果您看到多个 ID,那么您可能会遇到此问题.

这就是为什么您有时可能会看到延迟,但有时不会,应用程序代码使用会话的方式可能略有不同,或者页面之间的会话或 IO 操作可能更高或更低.

如果是这种情况,您可以采取一些措施来帮助加快速度,具体取决于网站或每个给定页面上会话的使用方式.

对于不修改会话的页面:

 

对于不使用会话状态的页面:

如果应用不使用会话(web.config):

<system.web><sessionState mode="关闭"/></system.web></配置>

那么让我们看下面的例子:

用户加载一个页面,然后在第一个请求完成加载之前决定转到另一个页面,ASP.NET 将强制会话锁定,导致新页面请求加载等待,直到第一个页面请求完成.使用 ASP.NET MVC,每个操作都会锁定用户会话以进行同步;导致同样的问题.

释放锁所花费的所有时间都会通过新的遗物报告,更不用说用户放弃会话并且返回的线程正在寻找不再存在的用户的时间.

>

顺便说一下,UpdatePanel 控件会导致相同的行为 -

http://msdn.microsoft.com/en-us/magazine/cc163413.aspx

可以做什么:

这个锁定问题是微软拥有 SessionStateUtility 类的原因之一 -

http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx

这样您就可以在遇到此问题时覆盖默认行为,如此处所示Redis 实现:https://github.com/angieslist/AL-Redis

基于 .net 的网站使用的默认状态提供程序有许多选项.但是一般知道这个事务时间表明线程被锁定并等待对服务器的请求完成.

We are using NewRelic to provide server-side application traces.

We have noticed that some of our applications consistently spend about 100ms in the method System.Web.Mvc.MvcHandler.BeginProcessRequest().

This happens before any custom controller code is called (which is logged separately, and not cumulatively) - it's not obvious why it would be spending so much time in this method.

What kinds of things will MVC do in this method? Could this simply be request queuing?

[EDIT:] As suspected - Scalayer's answer below was spot-on. We removed & optimized away all our session dependencies, and saw a massive increase in application scalability & stability

解决方案

What you might be seeing is commonly referred to as thread agility in .NET.

What you're probably seeing as far as the results underneath the topical label (i.e. Application code in System.Web.HttpApplication.BeginRequest()) is a thread agility problem; in most cases the time you see here isn't necessarily code being executed but the web context waiting for the threads to be released back to it from a reader-writer lock.

The Application_BeginRequest() "pause" is one that is pretty pervasive in a ASP.NET web stack. In general when you see long load times in BeginRequest, you are dealing with ASP.NET thread agility and/or thread locks - especially when dealing with IO and session based operations. Not that it's a bad thing, this is just how .net makes sure your threads remain concurrent.

The time gap generally occurs between BeginRequest and PreRequestHandlerExecute. If the application is writing several things to session then ASP.NET will issue a reader-writer lock on HttpContext.Current.Session.

A good way to see if this is an issue that you might be facing would be to check the thread IDs to see if agility is an issue - the IDs will be different for a given request.

For instance. While debugging, perhaps you could add the following to your Global.asax.cs:

protected void Application_BeginRequest(Object sender, EventArgs e) {
      Debug.WriteLine("BeginRequest_" + Thread.CurrentThread.ManagedThreadId.ToString());
   }

Open up the debug output window (From Visual Studio: View >> Output, then select "Debug" from the "show output from" dropdown).

While debugging, hit a page where you have seen the long time. Then view the output log - if you see multiple id's then you might be suffering from this.

This is why you might see the delay sometimes but not other times, the application code might be using session a little differently or session or IO operations might be higher or lower from page to page.

If this is the case some things you can do to help speed things up depending on how session is used on the site or each given page.

For pages that do not modify session:

   <% @Page EnableSessionState="ReadOnly" %>

For pages that do not use session state:

<% @Page EnableSessionState="False" %>

If the app does not use session (web.config):

<configuration>
    <system.web>
      <sessionState mode="Off" />
    </system.web>
</configuration>

So let's take the following example:

User loads a page, then decides to go to another page before the first request is done loading ASP.NET will force a session lock causing the new page request load to wait until the first page request finishes. With ASP.NET MVC each action locks the user session for synchronization; causing the same issue.

All of the time it took for the lock to be release will be reported via new relic, not to mention the ones where the user abandoned the session and the thread coming back is looking for a user who no longer exists.

Incidentally the UpdatePanel control causes the same behavior -

http://msdn.microsoft.com/en-us/magazine/cc163413.aspx

What can be done:

This locking problem is one of the reasons Microsoft has the SessionStateUtility class -

http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx

So that you can override the default behavior if you face this problem as seen here in thisRedis implementation:https://github.com/angieslist/AL-Redis

There are many options to the default state provider used by .net based websites. But know generally this transaction time indicates that threads are being locked and waiting on requests to the server to be completed.

这篇关于在 BeginProcessRequest() 中会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-16 19:18
查看更多