ASP.NET MVC:几分钟后第一次访问很慢,然后每个后续请求都很快

Posted

技术标签:

【中文标题】ASP.NET MVC:几分钟后第一次访问很慢,然后每个后续请求都很快【英文标题】:ASP.NET MVC: First access after some minutes slow, then every following request is fast 【发布时间】:2011-03-23 09:16:48 【问题描述】:

当我第一次访问我的 ASP.NET MVC 网站的任何页面时,第一次请求很慢。加载大约需要 4-5 秒。但是对任何页面的每个后续请求都很快。

当我等待几分钟或一个小时时,每个第一个请求都会再次变慢。每个后续请求都很快。

我认为 IIS 7 正在编译代码并将其保存在内存中。一段时间后它会从内存中删除它,所以它需要重新编译。

我该怎么做才能使每个第一个请求都与每个后续请求一样快? (如果可能,不要预编译我的源代码)

非常感谢您!

【问题讨论】:

如果您真的想加快速度,您需要做的是将所有内容预编译为 DLL,并在部署时将所有 DLL 编译为 NGEN,我们已经看到这可以减少高达 70% 的编译和 JIT 的时间成本可能很高 相关:***.com/questions/1422841/… 【参考方案1】:

如果这是一个生产服务器,那么为什么不尝试添加一个网站监视器;如up time robot。它基本上每 5 分钟询问您的网站标题并获取“200-ok”、“404-not found”等状态代码。这样,您的站点始终会启动并且不会影响日志文件/分析,因为仅请求标头。我将它用于我的云站点,因为我发现它们需要 5 秒才能启动,这会影响站点加载。有了显示器,它们是即时的。

哦,它最多可免费用于 50 个网站!

【讨论】:

【参考方案2】:

这可能是应用程序池上的回收工作进程设置,检查它的值并将其关闭或延长。

也可能是在应用程序池的性能下处于空闲状态后的 Shutdown 工作进程。

可能是第二个,因为默认为 20 分钟,我相信第一个默认为 29 小时。

【讨论】:

我使用的是 IIS 7。在哪里可以找到这些设置?这些只是 IIS 6 的设置吗? 不,它们在应用程序池的属性中【参考方案3】:

这几乎可以肯定是您的应用程序池空闲超时设置(而不是您正在重新编译的代码)。

IIS 中的默认应用程序池空闲超时为 20 分钟。这意味着,如果 20 分钟后没有请求进入您的应用程序,IIS 将关闭您的应用程序池的工作进程,使您的应用程序再次“冷”。发出下一个请求的人将等待几秒钟,因为 IIS 会重新启动工作进程并“预热”您的应用程序备份。

如果您不希望 IIS 在一段时间不活动后自动“冷却”您的应用,您可以通过将其设置为 0 来禁用应用池空闲超时。

【讨论】:

【参考方案4】:

假设您有固定的访问者流,这在生产中应该不是问题。此外,除非您在物理上更改任何源文件,否则 IIS 在启动您的应用程序时不会重新编译它。

另外,看看可用的 .NET 编译设置: http://technet.microsoft.com/en-us/library/cc725812(WS.10).aspx

【讨论】:

我目前是唯一的访客,因为我正在测试和开发 :-) 但是当我不更改文件但暂停一个小时时也需要很长时间。【参考方案5】:

tl;博士

经过相当广泛的测试和收集相关资源以尝试解决问题后,我认为最小的解决方案可能是(未验证)将此代码添加到 global.asax: p>

    protected void Application_End()
    
        ...
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://web_domain.tld");
        using (HttpWebResponse response = (HttpWebResponse)
            request.GetResponse())
        
        
        ...
    

在写这篇文章的时候,这被用来有效地维护我在“永远在线”上工作的网站——同时将 IIS 中的 Idle Time-out (minutes) 设置为 0,如其他答案中所述。 但是我认为更改Idle Time-out (minutes) 可能没有必要(假设在应用程序池切换到空闲模式时引发Application_end 事件)。

它是如何工作的(假设是这样):

    IIS 应用程序池设置中有 2 个设置会影响应用程序何时暂停或终止。其中之一是Idle Time-out (minutes),默认为 20 分钟,当指定的时间过去后自上次请求,工作进程将暂停或终止。当下一个请求到来时,工作进程将恢复或再次启动,并引发 Application_start 事件(因此如果在 global.asax 中定义了 Application_start 处理程序,则会执行它)。对于我从事的项目,Application_start 大约需要 17 秒才能完成。因此,如果该站点“被单独放置”了 21 分钟,然后新请求来了,则在发送回响应之前大约需要 17 秒多一点(Application_start + 页面处理)。当在 20 分钟的窗口内发送另一个请求时,响应的发送速度明显更快(可能不到 1 秒),因为 Application_start 已经被处理。

Idle Time-out (minutes) 值设置为 0 会导致工作进程为 never be suspended / terminated(至少由于空闲时间 - 可能还有下面描述的另一个原因)。

    除了Idle Time-out (minutes),IIS 高级设置的Recycling 部分还有Regular time interval (minutes) 设置。这默认为 1740 分钟(29 小时),是一个定期的计划任务,它会导致应用程序池定期回收(周期是固定的)。据我了解,这是为了防止可能的内存泄漏的累积,如果存在,可能最终通过耗尽所有内存而使服务器崩溃。应用程序池回收的效果是引发了 Application_end 事件。但是,在应用程序结束后它不会再次自动启动,因此在实际请求到来之前不会引发 Application_start 事件(这与第一种情况类似)。因此,在我处理的上述 Web 应用程序的情况下,在回收发生后处理第一个到达的请求再次需要大约 17 秒。将此值更改为 0 会关闭回收,但我认为不完全关闭回收是合理的,因为随着时间的推移可能会累积内存泄漏(这甚至可能是由 3rd 方库中的错误引起的)。我了解对于是否设置this value to 0 或not 存在不同意见,并且可能会随着时间而改变。

可能的解决方案(不更改 IIS 设置): 如果请求发送得足够频繁,则应用程序池可能永远不会切换到空闲模式。在回收的情况下,这也会导致应用程序重新启动。例如,这可以通过使用@Rippo 描述的第 3 方服务来实现。

建议的解决方案: 已观察到应用程序池回收导致引发Application_end 事件。假设它在应用程序池切换到空闲模式时也被引发,在Application_end 事件处理程序中向网站创建一个请求似乎就足够了,在这两种情况下都会导致应用程序再次启动(引发 Application_start 事件)。代码在答案的顶部。

【讨论】:

以上是关于ASP.NET MVC:几分钟后第一次访问很慢,然后每个后续请求都很快的主要内容,如果未能解决你的问题,请参考以下文章

如何跟踪 ASP.Net JIT 编译?它很慢

重新启动后,MVC 应用程序对于每个页面都很慢

关于asp.net Global.asax 我在 Application_Start有个定时器、每5分钟执行一次、一段时间后不执行了。

ASP.NET 应用程序每隔几分钟就会损坏一次视图状态

在 ASP.NET MVC 中过期后刷新访问令牌

ASP.NET MVC 中的唯一访问者计数