修复IIS初始加载缓慢问题

144

IIS有一个令人烦恼的特性,对于低流量的网站会回收未使用的工作进程,导致一段时间后访问该网站的第一个用户遇到极长的延迟(30秒以上)。

我一直在寻找解决方案,并找到了以下潜在解决方案。

A. 使用Application Initialization插件

B. 使用.NET 4的Auto-Start

C. 禁用空闲超时(在IIS重置下)

D. 预编译网站

我想知道哪种方法更好,更重要的是,为什么同一个问题有这么多解决方案?(我猜可能并不是这样,只是我理解有误)。

编辑

执行C似乎足以保持我的网站运行,但我发现我的网站慢的真正根源与Entity Framework有关,我无法弄清楚为什么它会变得缓慢。请参见问题,该问题已经得到了回答!

最终,我只好制作一个预热脚本,偶尔访问我的网站以确保它保持高速运行。


嗨朋友,只用C语言足够吗?为什么?我们只需要使用它还是需要禁用回收?我总觉得IIS7.5的第二天第一个请求非常缓慢。 - qakmak
7个回答

40

选项A、B和D似乎属于同一类别,因为它们只影响初始启动时间,就像编译和加载内存中的库一样对网站进行预热。

使用C设置闲置超时时间就足以使后续对服务器的请求快速响应(重新启动应用程序池需要相当长的时间——大约几秒钟)。

据我所知,这个超时存在是为了保存在该机器上并行运行的其他网站所需的内存。代价是一次缓慢的加载时间。

除了用户不活动时应用程序池被关闭之外,默认情况下,应用程序池也会每1740分钟(29小时)循环一次。

来自TechNet:

Internet Information Services(IIS)应用程序池可以定期回收,以避免不稳定状态导致应用程序崩溃、挂起或内存泄漏。

只要应用程序池回收保持开启,就足够了。但如果你真的想要大多数组件卓越的性能,你也应该使用像你提到的Application Initialization Module这样的东西。


那么你会建议禁用空闲超时吗?这样做会在以后引起问题吗(我猜它存在是有原因的)? - Cavyn VonDeylen
3
我明白您的意思,虽然这并没有解决我的问题(请看我编辑过的内容),但我还是接受了,因为您回答了我的原始问题。 - Cavyn VonDeylen

10

网站托管挑战

请记住,如果您的网站托管在共享服务器上,那么机器配置选项都将不可用,因为像我们这样的许多人(小型公司和个人)使用共享服务器。

ASP.NET MVC 开销

当我的网站在20分钟内没有被访问过(并且Web应用程序已停止)时,它至少需要30秒的时间。这太糟糕了。

另一种测试性能的方法

还有一种测试ASP.NET MVC启动或其他内容的方法。在您可以直接访问它的网站上放置一个普通的HTML页面。
如果问题与 ASP.NET MVC 启动有关,则即使 Web 应用程序未启动,HTML 页面也会几乎立即呈现。
这就是我最初认识到问题出现在ASP.NET MVC启动中的方式。 我随时加载一个 HTML 页面,它加载非常快速。然后,在访问了该 HTML 页面之后,我会访问我的某个 ASP.NET MVC URL,然后我会收到 Chrome 消息“等待raddev.us...”

使用有用的脚本进行另一个测试

之后,我编写了一个 LINQPad(查看http://linqpad.net获取更多信息)脚本,每8分钟(小于应用程序卸载的时间-应该是20分钟)访问我的网站,并让它运行数小时。

脚本运行时,我访问我的网站,每次都能快速加载我的网站。这使我很有信心,我经历的缓慢很可能是由于 ASP.NET MVC 启动时间过长导致的。

获取 LinqPad 并运行以下脚本--仅更改 URL 为您自己的,让它运行,您可以轻松测试这一点。 祝好运。

注意:在 LinqPad 中,您需要按F4并添加对 System.Net 库的引用,以检索您的页面。

另外:确保将字符串URL变量更改为指向从ASP.NET MVC站点加载路由的URL,以便引擎运行。

System.Timers.Timer webKeepAlive = new System.Timers.Timer();
Int64 counter = 0;
void Main()
{
    webKeepAlive.Interval = 5000;
    webKeepAlive.Elapsed += WebKeepAlive_Elapsed;
    webKeepAlive.Start();
}

private void WebKeepAlive_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    webKeepAlive.Stop();
    try
    {
        // ONLY the first time it retrieves the content it will print the string
        String finalHtml = GetWebContent();
        if (counter < 1)
        {
            Console.WriteLine(finalHtml);
        }
        counter++;
    }
    finally
    {
        webKeepAlive.Interval = 480000; // every 8 minutes
        webKeepAlive.Start();
    }
}

public String GetWebContent()
{
    try
    {
    String URL = "http://YOURURL.COM";
    WebRequest request = WebRequest.Create(URL);
    WebResponse response = request.GetResponse();
    Stream data = response.GetResponseStream();
    string html = String.Empty;
    using (StreamReader sr = new StreamReader(data))
    {
        html = sr.ReadToEnd();
    }
    Console.WriteLine (String.Format("{0} : success",DateTime.Now));
    return html;
    }
    catch (Exception ex)
    {
        Console.WriteLine (String.Format("{0} -- GetWebContent() : {1}",DateTime.Now,ex.Message));
        return "fail";
    }
}

3
编写一个ping服务/脚本来访问您的空闲网站是相当好的选择,因为您将拥有完全的控制权。如果您租用了专用主机,其他选项也将可用。
在共享主机空间中,预热脚本是最好的第一级防御(自助是最好的帮助)。这里有一篇文章分享了如何从您自己的Web应用程序进行操作的想法。

刚刚更新了这个旧帖子,以防有人搜索相同的内容。 - David Chelliah

2
请参考此文章中有关如何解决性能问题的提示。其中包括与“冷启动”相关的性能问题。无论您使用什么类型的服务器,无论是本地还是在生产环境中,大多数内容都很重要。 https://blogs.msdn.microsoft.com/b/mcsuksoldev/2011/01/19/common-performance-issues-on-asp-net-web-sites/

如果应用程序从XML反序列化任何内容(包括Web服务…),请确保针对涉及到反序列化的所有二进制文件运行SGEN,并将生成的DLL放置在全局程序集缓存(GAC)中。这会预编译SGEN针对的程序集使用的所有序列化对象,并将它们缓存在生成的DLL中。这可以极大地节省首次从磁盘加载配置文件和调用Web服务时的时间。

http://msdn.microsoft.com/en-us/library/bk3w6240(VS.80).aspx

如果任何IIS服务器无法访问互联网,请通过向machine.config添加generatePublisherEvidence =“false”来关闭Authenticode二进制文件的证书吊销列表(CRL)检查。否则,每个工作进程在启动时都会挂起超过20秒钟,因为它超时尝试连接到互联网以获取CRL列表。

http://blogs.msdn.com/amolravande/archive/2008/07/20/startup-performance-disable-the-generatepublisherevidence-property.aspx

http://msdn.microsoft.com/en-us/library/bb629393.aspx

考虑对所有程序集使用NGEN。但是,如果不小心使用,这并不能带来太多性能提升。这是因为每个进程加载的所有二进制文件的基本加载地址必须在构建时仔细设置,以避免重叠。如果二进制文件在加载时必须重新定位,因为地址冲突,那么使用NGEN的几乎所有性能增益都将丧失。

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

2
一个很好的定时ping网站的选项是使用微软Flow,每月免费提供750次“运行”。创建一个每小时访问您的网站的Flow非常容易,以保持其活跃。您甚至可以通过创建一个单一的Flow,在多次访问您的网站之间设置延迟来绕过750的限制。 https://flow.microsoft.com

2
我会选择B,因为它与工作进程回收结合使用,意味着只有在回收期间才会有延迟。这避免了响应空闲后的第一个请求时通常与初始化相关的延迟。您还可以保留回收的好处。

0
我在应用程序首次请求时遇到了15秒的延迟,但只有在4分钟没有操作后才会出现。我的问题是我的应用程序使用了Windows集成身份验证连接SQL Server,而服务配置文件位于与服务器不同的域中。这导致IIS到SQL之间出现跨域身份验证,从而导致了我的延迟。我改为使用SQL登录而不是Windows身份验证。延迟立即消失了。我仍然保留了所有应用程序初始化设置以提高性能,但在我的情况下可能根本不需要它们。

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