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

25

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

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

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

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

非常感谢您的帮助!


如果你真的想加快速度,你需要将所有东西预编译为DLL,并在部署时对所有DLL进行NGEN处理。我们已经看到这可以减少高达70%的时间,因为编译和JIT可能是一个很大的成本。 - Carlos Aguilar Mares
相关链接:https://dev59.com/WHM_5IYBdhLWcg3wUxjF - Artur Carvalho
5个回答

22
如果这是一台生产服务器,为什么不尝试添加一个网站监控器,比如up time robot。它基本上会请求您的网站头并获取状态代码,如“200-ok”,“404-not found”等,每5分钟一次。这样,您的网站始终处于运行状态,并且不会影响日志文件/分析,因为只有头被请求。我在我的云端站点中使用它,因为我发现它们需要5秒钟才能启动,这对网站加载有影响。有了监视器,它们就可以立即启动。

哦,而且免费支持50个站点!


17

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

也可能是由于应用程序池性能下闲置后关闭工作进程。

很可能是第二个原因,因为默认设置为20分钟,而第一个默认设置为29小时左右。


我正在使用IIS 7。我在哪里可以找到这些设置?这些只是适用于IIS 6的设置吗? - Chris
不,它们在应用程序池的属性中。 - BlackICE

5
这几乎可以确定是您的应用程序池空闲超时设置问题(而不是您的代码被重新编译)。在IIS中,默认的应用程序池空闲超时为20分钟。这意味着,如果20分钟过去了并且没有任何请求进入您的应用程序,则IIS将关闭应用程序池的工作进程,使您的应用程序再次“冷却”。下一个请求者将等待几秒钟,因为IIS重新启动工作进程并 “热” 您的应用程序。如果您不希望IIS在一段时间内自动“冷却”您的应用程序,则可以通过将其设置为0来禁用应用程序池空闲超时。

1

我目前是唯一的访问者,因为我正在测试和开发 :-) 但是当我不修改文件而暂停一个小时时,它也需要很长时间。 - Chris

0

简而言之

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

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

在撰写本文时,这被用于有效地维护我所工作的网站始终处于“运行”状态 - 与在其他答案中提到的将IIS中的Idle Time-out(分钟)设置为0相结合。 然而,我认为改变Idle Time-out(分钟)可能并不必要(假设在应用程序池切换到空闲模式时引发了Application_end事件)。

它的工作原理(假设它确实起作用):

在IIS应用程序池设置中有两个设置会影响应用程序何时被挂起或终止。其中之一是空闲超时(分钟),默认为20分钟,当自上次请求以来经过指定时间后,工作进程将被挂起或终止。当下一个请求到来时,工作进程将恢复或重新启动,并引发Application_start事件(因此,如果在global.asax中定义了Application_start处理程序,则会执行它)。在我所工作的项目中,Application_start需要大约17秒才能完成。因此,如果网站“独自一人”21分钟,然后新请求到来,那么在发送响应之前需要大约17秒左右(Application_start +页面处理)。当在20分钟的窗口期内发送另一个请求时,响应速度显着加快(可能少于1秒),因为Application_start已经被处理。
空闲超时(分钟)值设置为0会导致工作进程永远不会被挂起/终止(至少由于空闲时间 - 可能存在下面描述的其他原因)。
除了“空闲超时(分钟)”之外,在IIS高级设置的“回收”部分还有“定期时间间隔(分钟)”设置。此默认值为1740分钟(29小时),是定期计划任务,会导致应用程序池定期重启(周期固定)。我理解这是为了防止可能存在的内存泄漏累积,如果存在,可能会通过耗尽所有内存最终崩溃服务器。应用程序池重启的效果是引发Application_end事件。但是,在应用程序结束后,它不会自动重新启动,因此直到实际请求到来(类似于第一种情况),才会引发Application_start事件。因此,在我所工作的前述Web应用程序的情况下,再次处理第一个请求需要大约17秒。将此值更改为0可关闭回收,但我认为由于内存泄漏可能随着时间的推移而积累(甚至可能由第三方库中的错误引起),不完全关闭回收是合理的。我理解对于是否将该值设置为0的观点存在分歧,并且随时可能发生变化。

可能的解决方案(无需更改IIS设置): 如果请求被频繁发送,应用程序池可能永远不会切换到空闲模式。在回收事件发生时,这也会导致应用程序重新启动。例如,可以使用@Rippo描述的第三方服务来实现此目的。

建议的解决方案: 观察到应用程序池回收会导致引发Application_end事件。假设它在应用程序池切换到空闲模式时也会引发,那么在Application_end事件处理程序中向网站创建一个请求似乎就足以使应用程序重新启动(引发Application_start事件)。代码位于答案顶部。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接