【问题标题】:Mysterious ASP.NET MVC Action High latency issue?神秘的 ASP.NET MVC Action 高延迟问题?
【发布时间】:2011-05-30 04:43:49
【问题描述】:

使用 Firebug 和 Chrome 开发人员工具,我可以看到通过一个操作加载一些 javascript 和 css 文件在我的开发机器上可能需要额外的 500 毫秒。这发生在不同调用的不同文件上,不管我把它们放在什么顺序。如果我直接链接到这些文件,这 500 毫秒的延迟永远不会发生。我可以一遍又一遍地刷新页面并获得不同的值,但它们看起来总是像请求时间增加了 500 毫秒。如果我不断刷新页面,额外的 500 毫秒会显示在不同的单个文件上,有时会显示在两个文件上,其中一个文件有 1000 毫秒的延迟,如下图所示。


编辑

将 Monitor.Enter 放入我的 HttpModule 的 BeginRequest 和 Monitor.Exit 放入 EndRequest 导致延迟消失,所以我猜它与线程化多个请求有关。


我使用 Evan Nagel here 描述的方法进行缓存,但是当我将链接替换为对我自己的控制器的调用时,会发生同样的事情,该操作只传递一个原始文件:

public FileResult RawFile(string path, string contentType)
{
    var server = HttpContext.Server;
    string decodedPath = server.UrlDecode(path);
    string mappedPath = server.MapPath(decodedPath);
    return File(mappedPath, contentType);
}

这是我在我的 html 的 head 部分中的代码:

<link rel="stylesheet" href="@Url.Action("RawFile", new { controller = "Content", path = "~/Content/Site.css", contentType = "text/css" })" type="text/css" />
<script src="@Url.Action("RawFile", new { controller = "Content", path = "~/Scripts/debug/FBINFO.js", contentType = "application/x-javascript" })" type="text/javascript"></script>
<script src="@Url.Action("RawFile", new { controller = "Content", path = "~/Scripts/jquery-1.4.1.min.js", contentType = "application/x-javascript" })" type="text/javascript"></script>

这似乎不会在我的生产服务器上发生,至少不会经常发生,但由于延迟通常较高,所以很难说。这是不用担心的事情吗?什么会导致它? Cassini 和我在 Windows 7 Home Ultimate 64 位上的本地 IIS 服务器都会发生这种情况。

我添加了一个自定义属性来计时调用,并且 OnAction/OnResult Executing 和 Executed 之间的时间通常是亚毫秒。我在 action 方法周围使用了秒表(ZipController 写入响应流并且不返回结果),时间同样总是很小,平均 1.5 毫秒并且总是低于 10 毫秒。

我在 Fiddler 标头中看到的唯一真正区别是 X-AspNetMvc-Version 标头,因此我将其设置为不附加,甚至删除 X-AspNet-Version 标头也无济于事。我已经尝试过启用和禁用压缩以及我能想到的所有其他内容。这是在我添加了我自己的 Cache-Control 和 ETag 标头之后,这些标头没有任何效果。有趣的是,即使在未发送正文的 304 Not Modified 响应的情况下也会发生 500 毫秒的延迟。有时两个文件会有延迟,一个是 500 毫秒,另一个是 1000 毫秒。

直接文件:

HTTP/1.1 200 OK
Content-Type: application/x-javascript
Last-Modified: Sun, 29 May 2011 22:42:27 GMT
Accept-Ranges: bytes
ETag: "b57a84af511ecc1:0"
Server: Microsoft-IIS/7.5
Date: Mon, 30 May 2011 04:38:20 GMT
Content-Length: 1336

原始文件操作:

HTTP/1.1 200 OK
Cache-Control: public
Content-Type: application/x-javascript
ETag: "CD9F383D0537373C6D2DC8F60D6519A6"
Server: Microsoft-IIS/7.5
Date: Mon, 30 May 2011 04:34:37 GMT
Content-Length: 1336

根据 IanT8 的评论,我添加了一个 HttpModule 来跟踪开始/结束请求,并将日志调用添加为我的操作方法的第一个和最后一个语句。长话短说,两个请求同时进来,500ms 的延迟发生在第一个 EndRequest 之后,第二个调用的 action 方法执行之前。这个延迟一般是499ms,但是一次是497ms,一次是498ms,一次是492ms。

2011-05-31 00:55:19.1874|INFO|20110531 00:55:19.196 BeginRequest: http://localhost:51042/Zip/Style?Path=~/Content/Site.css
2011-05-31 00:55:19.1874|INFO|20110531 00:55:19.197 BeginRequest: http://localhost:51042/Zip/Script?Path=~/Scripts/jquery-1.4.1.min.js|~/Scripts/debug/FBINFO.js
2011-05-31 00:55:19.2034|INFO|20110531 00:55:19.203 Style() Start
2011-05-31 00:55:19.2034|INFO|20110531 00:55:19.208 Style() End
2011-05-31 00:55:19.2034|INFO|20110531 00:55:19.212 EndRequest: http://localhost:51042/Zip/Style?Path=~/Content/Site.css
2011-05-31 00:55:19.7044|INFO|20110531 00:55:19.704 Script() Start
2011-05-31 00:55:19.7044|INFO|20110531 00:55:19.712 Script() End
2011-05-31 00:55:19.7044|INFO|20110531 00:55:19.713 EndRequest: http://localhost:51042/Zip/Script?Path=~/Scripts/jquery-1.4.1.min.js|~/Scripts/debug/FBINFO.js

现在是真正有趣的部分。我在 HttpModule 上创建了一个静态对象,并在 BeginRequest 中调用 Monitor.Enter,在 EndRequest 中调用 Monitor.Exit。延迟消失了。 Chrome 显示一个呼叫大约需要 15-20 毫秒,另一个大约需要 30-40 毫秒,因为它必须等待第一个呼叫结束,但 500 毫秒的延迟已经消失。显然这个解决方案不是最优的。

【问题讨论】:

  • 你考虑过动作的编译时间吗?您可以通过检查后续调用来对此进行测试。
  • 是的,我会在问题中添加注释。
  • 这与我在服务器故障中发现的这个限制有什么关系吗? MS 真的想让我们的开发机器对这种测试几乎毫无用处吗?每次调用添加的几乎精确的 500 毫秒让我认为它可能是这样的。 serverfault.com/questions/133772/…
  • 我知道在 Firefox 中调试时,我在使用 localhost 查看页面时会遇到高延迟,但是使用 127.0.0.1 时会快得多。 Chrome 也可以这样吗?
  • 您是否考虑过通过挂钩开始请求/结束请求事件来添加一个 Http 模块来计时并记录所花费的时间。至少你会知道在 asp.net mvc 中花费了多少时间。

标签: asp.net-mvc asp.net-mvc-3


【解决方案1】:

尝试禁用会话 (SessionStateAttribute)。

【讨论】:

  • 这让它不会发生,但我真的很想使用会话变量...你认为这是一个 MVC 错误吗?
  • @Jason 对会话使用操作的请求总是在 ASP.NET 中序列化以避免并发问题。对于这些对静态文件的请求,您真的需要会话状态吗?
  • 啊,由于某种原因,我错过了它是一个属性,只知道如何为 Web.config 中的所有内容禁用它。使用该属性有效。
  • 序列化是什么意思?为什么会导致 500 毫秒的延迟?
  • @Jason 我的意思是,来自同一个会话(即同一个用户)对使用会话状态的操作(或 Web 表单,在 ASP.NET Web 窗体中)的请求默认情况下在每个其他。这是因为一个用户的会话状态可能会同时被两个不同的 ASP.NET 工作线程改变,这可能会导致灾难。这不会导致 500 毫秒的延迟,但在这里可能仍然相关,因为一个请求会“等待另一个”。 (我无法在此处提供适当的引文,因为我找不到。)
【解决方案2】:

Cassini 存在一个已知问题以及与 IPv4 上的 IPv6 主机文件映射相关的性能问题,以及 Cassini 在 Windows 7 下使用的端口号解析。 Stack Overflow 上的 already answered 解决了 Firefox 和 Chrome 中出现的问题.

【讨论】: