zoukankan      html  css  js  c++  java
  • IIS+ASP.NET MVC必须知道的事

    来源:东汉

    cnblogs.com/michaeldonghan/p/9277302.html


    问题现象


    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


    640?wx_fmt=png


    要确定有安装IIS应用程序初始化功能,如下图


    640?wx_fmt=png


    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 = "http://localhost:8001/home2/about";

                 using (var webClient = new WebClient())

                 {

                     webClient.DownloadStringAsync(new Uri(url));//要异步请求

                 }

             }

             catch (Exception e)

             {

                 MvcApplication.DoLogToTxt("Preload Error:" + e.Message);

             }

         }

    }


    2、修改IIS配置文件,让IIS能识别到刚写的ApplicationPreload类


    打开IIS配置文件:%WINDIR%System32inetsrvconfigapplicationHost.config 


    <applicationPools>

        <add name="MyAppWorkerProcess" managedRuntimeVersion="v4.0" startMode="AlwaysRunning" /> <!-- 上面我们在IIS程序池界面中有设置过startMode项为AlwaysRunning-->

    </applicationPools>


    <!-- ... -->


    <sites>

        <site name="MySite" id="1">

            <application path="/" serviceAutoStartEnabled="true" serviceAutoStartProvider="ApplicationPreload" />

        </site>

    </sites>

    <serviceAutoStartProviders>

        <add name="ApplicationPreload" type="WebApplication1.ApplicationPreload, WebApplication1" />

    </serviceAutoStartProviders>


    最后一个条目的type,其中WebApplication1.ApplicationPreload是应用程序中实现IProcessHostPreloadClient接口的类的全名,WebApplication1是程序集名称。 


    设置完这两步也就搞定了启动站点时自动访问站点。 


    探讨


    在上面设置之前,我测试只更新站点部分dll,第一次访问需要1~4秒,测试的站点是含有CMS源码的站点,不算小了。


    之前有个面试官说他们公司站点更新一个dll,第一次访问需要10~30秒,甚至更久,这样正在访问站点的用户就要等待,然后一直在报怨IIS和.Net,想要投奔java的怀抱(这里不比较两种语言,它们各自有自己的优势),我问他是不是在Global.asax里Application_Start做了太多自己的初始化,要么有些初始化在用户访问到时处理负担分担出去,要么Application_Start异步处理初始化动作,但是他说这些自己的初始化都是用户访问前必须初始化好的。


    这应该是自己系统设计不够好不能怪.NET,如果是用了七七八八的第三方组件,比如EF初始化慢,那就换成轻量级的Dapper,然后好好学习一下《N种提升Asp.Net Mvc性能的方法》不要闭门造车。


    (你们更新一个站点的dll,第一次访问需要多少秒呢?)


    那么,在上面设置之后 ,如果更新站点dll后第一次访问需要1~4秒的情况下,系统自动帮你做了第一次访问,很可能正在访问的用户就不怎么察觉得出来站点有重启过。


    如果是高并发访问的大型网站,那就应该有负载均衡(IIS可以用NLB做负载均衡,或考虑CDN或DNS解析时就做负载均衡),应该有分布式等。


    最后 ,如果你的站点是因为更新dll而导致站点重启,而且对此问题深恶痛绝,那么可以用.NET的动态加载dll来解决,不是用AppDomain动态加载和卸载dll(这个太麻烦),而是用Assembly.LoadFile加载dll。


    比如Controller所在的dll是MvcA.dll,它引用了LibA.dll,当这两个dll都有修改时,如何让站点加载到这两个最新版本的dll。




  • 相关阅读:
    ffmpeg显示视频
    眼见为实(1):C++基本概念在编译器中的实现
    在Windows系统上实现轻量级的线程间及进程间消息队列
    Intellij IDEA 2017 debug断点调试技巧与总结详解篇
    redis 全局命令 查看所有的键,删除键,检查键是否存在,获取过期时间,键的数据结构类型
    java.security.InvalidKeyException: IOException : Short read of DER length
    RSA解密报错java.security.spec.InvalidKeySpecException的解决办法
    IntelliJ IDEA全局内容搜索和替换
    RSA加密/解密 Decryption error异常解决
    java rsa 解密报:javax.crypto.BadPaddingException: Decryption error
  • 原文地址:https://www.cnblogs.com/hgmyz/p/12351763.html
Copyright © 2011-2022 走看看