IIS+Asp.Net Mvc必須知道的事(解決啟動/重啟/自動回收站點后第一次訪問慢問題)


問題現象:

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 = "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%\System32\inetsrv\config\applicationHost.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。這個可以解決的,如果實際應用中需要此需求的人多(請回復評論),我會再整理分享出來。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM