59

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

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

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

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

[编辑:]怀疑 - Scalayer 在下面的回答是正确的。我们删除并优化了所有会话依赖项,并看到应用程序可扩展性和稳定性大幅提高

4

4 回答 4

87

您可能会看到在 .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()); 
   }

打开调试输出窗口(从 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,每个操作都会锁定用户会话以进行同步;导致同样的问题。

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

顺便说一句,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 的网站使用的默认状态提供程序有很多选项。但是通常知道这个事务时间表明线程被锁定并等待对服务器的请求完成。

于 2013-06-12T18:54:43.570 回答
6

如果你想让某个控制器并行处理来自单个用户的请求,你可以使用从版本 3 开始在 MVC 中引入的名为 SessionState 的属性。不需要使用无会话控制器来实现并行性, SessionStateBehavior 的 Ready-only 选项可让您通过您可能已根据 Session 数据实施的安全检查。

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

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

于 2014-03-20T17:42:05.037 回答
2

我在一个使用会话很少的应用程序中遇到了同样的问题。在考虑到接受的答案后,甚至出于诊断目的暂时完全删除 SessionState 后,我在这个“方法”中的性能仍然存在重大问题

根据 todd_saylor 在这个帖子中的评论,我在自己的网站上做了很多研究,发现它BeginProcessRequest可以作为 New Relic 对出现在不同代码区域的各种性能损失的包罗万象。通过使用 Red Gate 的 ANTs Performance Profiler 在我的本地机器上分析代码,我能够显着减少这方面的时间。

我的本地分析揭示了一些事情:

  1. 我使用 Ninject 作为我的 DI 容器,这导致其对象解析的性能损失。我用 SimpleInjector 替换了它,并将性能提高了一个数量级。
  2. 我发现在 AutoMapper 的 IQueryable ExtensionsProject().To<>()和 Linq 的 Sql Server 提供程序之间的某个地方,预测的动态编译和 JITing 占了我请求时间的 50%。用 CompiledQuerys 替换它又产生了重大影响。

希望这对其他人有帮助!

于 2015-04-03T19:26:24.233 回答
0

对于阅读此无法解释的 IIS 高 CPU 使用率的任何人,请查看我打开的 NewRelic 支持论坛中的此线程。

我已经处理这个问题一个多星期了,直到我意识到问题的根本原因是他们的代理。

.NET 代理在 IIS 上导致高 CPU 使用率

所以我建议您尝试的第一件事是删除 .NET 代理并查看是否有任何变化,然后再进行更复杂的实验。

我在这个特定问题上发布了这个答案,因为我在处理这个问题时首先来到这里,并且线程敏捷性让我走上了一个不正确的长期课程......(虽然它本身很有趣)。

于 2014-09-17T06:29:18.903 回答