[ASP.NET]監控ASP.NET執行緒(w3wp)狀態

asp.net一旦重新啟動後,網頁的首次啟動效率都比平時使用慢上許多,過去在台灣客戶對這一點並不這麼在意,畢竟每個網頁只慢第一次執行,但最近陸續有兩家客戶跟我們抱怨這一點,並說這是因為我們程式寫法的問題,這真是有苦難言,因為不管是.net或者java,程式在第一次執行時都會比較慢一些,但這些專頁內容並不是客戶想聽的,我們也只有大略帶過,摸摸鼻子還是要解決這個問題。

不知道這篇要如何命名比較好,姑且就叫這名字吧。

w3wp是IIS6以後ASP.NET執行的處理序,這個處理序在幾種狀態下會被重新啟動:

1.process crash時:可能因為例外狀況過多、memory使用量過大、死結等等問題

2.IISReset

3.被回收(時間到、request數目達到、記憶體等等..)

而一旦重新啟動後,網頁的首次啟動效率都比平時使用慢上許多,過去在台灣客戶對這一點並不這麼在意,畢竟每個網頁只慢第一次執行,但最近陸續有兩家客戶跟我們抱怨這一點,並說這是因為我們程式寫法的問題,這真是有苦難言,因為不管是.net或者java,程式在第一次執行時都會比較慢一些,但這些專頁內容並不是客戶想聽的,我們也只有大略帶過,摸摸鼻子還是要解決這個問題。

由於此現象在以前早就知道了,也曾經找過一些解決方案,但發現測試後都沒太大的效果,最後想出了一個偏方,思路是這樣的:既然第一次會慢,那我不要讓使用者有機會去執行那第一次不就好了?所以就想到要監控w3wp的狀態,只要w3wp被重新啟動後,我就自動讓所有常用的網頁自動先執行一次,而要做到這一點,就需要監控w3wp處理序,上網查了一下取得process資訊的方法,後來找到下面這一段:

01     public class W3wpProcess
02     {
03         /// <summary>
04         /// 取得目前應用程式的w3wp的processid,用來監控processid是否有換,有換的話就要啟動autorun
05         /// </summary>
06         /// <param name="pNowPid">要抓的應用程式名稱,就是AppPool的名稱</param>
07         /// <returns>A應用程式:3006,B應用程式:3009:丟A進來回傳3006,到時候就是監控3006</returns>

08         public static string getW3wp(string pNowPid, string pCheckProcName)  
09         {
10             ObjectQuery tQuery = new ObjectQuery(String.Format("select * from Win32_Process where Name='{0}'", pCheckProcName));  
11             ManagementObjectSearcher tSearcher = new ManagementObjectSearcher(tQuery);  
12             ManagementObjectCollection tReturnCollection = tSearcher.Get();  
13             
14             string tPid="";  
15             string tCmdLine;
16             
17             foreach(ManagementObject tReturn in tReturnCollection)  
18             {  
19                 tPid = tReturn.GetPropertyValue("ProcessId").ToString();  
20                 tCmdLine = (string)tReturn.GetPropertyValue("CommandLine");
21
22                 string tPattern = "-ap \"(.*)\"";
23                 Regex tRegex = new Regex(tPattern, RegexOptions.IgnoreCase);
24                 Match match = tRegex.Match(tCmdLine);  
25                 string tAppPoolName = match.Groups[1].ToString();
26                 //如果找到要找的那個AppPool就break,因為那個processid就是我要的了
27                 if (pNowPid == tAppPoolName)
28                 {
29                     break;
30                 }

31             }

32
33             return tPid;  
34         }

35     }

這一段程式可以取得目前處理序的ID,而因為在IIS6.0以後的版本可以切分多AppPool,所以這個function也可以針對不同的AppPool做處理,這個function是核心,而我使用的概念是這樣:

1.啟一個常駐的服務,此服務的目的是在定時偵測w3wp處理序的processid是否有改變

2.服務一啟動時先取得目前要監控的processid(A)

3.定時比對目前對應的AppPool的processid跟processid(A)是否相同,如果不同就自動執行網頁

4.再回復到以上的循環

透過這樣的監控機制,終於也解決了此問題,目前看來要從.net framework去改變這個結果似乎有點困難,還是需要靠自己想些辦法了。

游舒帆 (gipi)

探索原力Co-founder,曾任TutorABC協理與鼎新電腦總監,並曾獲選兩屆微軟最有價值專家 ( MVP ),離開職場後創辦探索原力,致力於協助青少年培養面對未來的能力。認為教育與組織育才其實息息相關,都是在為未來儲備能量,2018年起成立為期一年的專題課程《職涯躍升的關鍵24堂課》,為培養台灣未來的領袖而努力。