Asp.net Mvc站点部署在IIS上后,第一个用户第一次访问站点,都会比较慢,确切的说是访问站点的Action页面(即非静态页面,因为静态页面直接由IIS处理返回给用户即完成请求,而Action页面IIS要转交给Aspnet_Wp工作进程,进而涉及相关初始化操作,这些初始化操作是比较慢的。第二次访问站点就不需要再初始化了所以就快了)。
这种第一次访问慢的问题不仅发生在网站第一次部署启动,也发生在站点重启和站点程序池回收(经测试,第一次部署启动初始化所用时间会多一些,然后是站点重启,然后是站点回收)。
1.站点重启包含手动重启和修改web.config配置、修改IIS上站点配置、更新站点bin目录的dll等引起的自动重启。如果你的站点是新上线的web或者会持续修改添加功能的web,那难免会更新dll导致重启。其它编译型语言(比如java)也是如此,更新了服务端组件,都难免要重启站点。这边会分享.net环境下如何优化此问题;
2.站点程序池回收是IIS建议的,本来默认是29小时回收一次。为什么要建议回收呢,大致可以这样理解:一个每日定时回收的机制就像是在发生轻微内存泄露或者其它拖累Worker进程的因素的情况下,刷新IIS的良药,站点回收即节省了资源又提高了稳定性。然而,自动回收后第一次访问慢的问题困扰了许多人,其实只要稍微设置就可以解决,即没有困扰也拥有了回收的优点。
问题解决:
1.先在IIS上设置相应应用程序池的“高级设置”(IIS版本要在8或8以上,要知道IIS10早已出来了,如果你在用IIS很低的版本,然后在报怨IIS,我...),如下图,这样设置后,回收只会发生在凌晨04:00:00
要确定有安装IIS应用程序初始化功能,如下图
2.在IIS上设置站点的“高级设置”,把【预加载已启用】设置为true。
设置完这两步,当站点(自动)回收时,访问站点也是秒开不受任何影响,它的原理是在回收时会保持站点持续运行,这样的回收可以理解为把旧的Worker内容平滑的移到新的Worker上,然后回收掉旧的Worker。但是要注意,回收会导致站点内存信息丢失,因此如果你的设计是把session放在内存,则就要设置永不自动回收,那只要在第1步的基础上把【特定时间】清空即可。不过我个人会建议你不要设计session放内存,你更新个dll导致站点重启,内存也是清空的,你不如把session放在memcache/redis中,如果你的系统还没用上这些,那你就用cookie代替session吧,cookie更灵活适用的场景也更多。
现在回收的问题完美解决了,接下来说说站点重启。站点重启肯定是要重新加载配置重新加载dll(不想重新加载dll的,看文章最后一段),初始化是免不了,默认重启后第一个用户第一次访问站点会触发初始化,那么我们可以在站点启动/重启时,系统自动发一个站点请求,让系统自己尝尝第一次访问慢的问题。
IIS站点启动时机自动请求站点1.启动站点时触发的时机
创建一个类,继承自IProcessHostPreloadClient接口,其Preload方法就是启动站点时触发。然后在里面自动访问站点,如下代码:
public class ApplicationPreload : System.Web.Hosting.IProcessHostPreloadClient { public void Preload(string[] parameters) { try { //自动请求的url,其中http://localhost:8001 最好配置在config中,这边只是演示。 string url = ":8001/home2/about"; using (var webClient = new WebClient()) { webClient.DownloadStringAsync(new Uri(url));//要异步请求 } } catch (Exception e) { MvcApplication.DoLogToTxt("Preload Error:" + e.Message); } } }