BeginProcessRequest()会发生什么?

Dav*_*ish 58 c# asp.net asp.net-mvc-3 newrelic

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

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

出现这种情况的任何自定义控制器代码调用之前(这是单独记录,而不是累积) - 这不是显而易见的,为什么会在这种方法中花费这么多的时间.

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

[编辑:] 如怀疑 - Scalayer的回答是现实的.我们删除并优化了所有会话依赖关系,并看到了应用程序可伸缩性和稳定性的大幅提升

小智 86

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

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

Application_BeginRequest()"暂停"是一个在ASP.NET Web堆栈中非常普遍的"暂停".通常,当您在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()); 
   }
Run Code Online (Sandbox Code Playgroud)

打开调试输出窗口(从Visual Studio:View >> Output,然后从"show output from"下拉列表中选择"Debug").

在调试时,点击您已经看过很长时间的页面.然后查看输出日志 - 如果你看到多个id,那么你可能会受此影响.

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

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

对于不修改会话的页面:

   <% @Page EnableSessionState="ReadOnly" %>
Run Code Online (Sandbox Code Playgroud)

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

<% @Page EnableSessionState="False" %>
Run Code Online (Sandbox Code Playgroud)

如果应用程序不使用session(web.config):

<configuration>
    <system.web>
      <sessionState mode="Off" />
    </system.web>
</configuration>
Run Code Online (Sandbox Code Playgroud)

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

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

锁定被释放所花费的所有时间都将通过新文件进行报告,更不用说用户放弃会话并且回来的线程正在寻找不再存在的用户.

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

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

可以做些什么:

此锁定问题是Microsoft拥有SessionStateUtility类的原因之一 -

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

因此,如果遇到此问题,您可以覆盖默认行为,如此Redis实现中所示:https://github.com/angieslist/AL-Redis

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

  • 我们不使用Sesssions,我们已禁用它们,我们仍然看到这个问题. (8认同)
  • 我知道这是一个古老的问题,但我和道格,同样的问题,没有使用塞申斯! (4认同)
  • 感谢您对这个问题给出了如此精彩的答案 - 我强烈认为您是正确的,就像在相关页面上一样 - 我们很可能会执行大量繁琐的会话操作. (2认同)

And*_*nka 6

如果要使某个控制器能够从单个用户并行处理请求,则可以使用自版本3以来在MVC中引入的名为SessionState的属性.为了实现并行性,不必使用无会话控制器, SessionStateBehavior的Ready-only选项将允许您通过基于会话数据实现的安全检查.

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public class ParallelController : Controller
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

我也有延迟System.Web.Mvc.MvcHandler.BeginProcessRequest(),当我尝试做一些长时间运行的行动时,我看到它NewRelic.此属性解决了问题,并为处理此控制器的并行操作提供了能力.