項目中遇到的問題
排查原因
最近調(diào)試一個東西,寫了個監(jiān)控頁面,發(fā)現(xiàn)自己Cache的數(shù)據(jù)在設(shè)定的過期時間遠遠還沒有到的時候就過期了,于是我著手排查了下出現(xiàn)問題的原因:
1、程序會刪除緩存 -- 查找了整個項目,發(fā)現(xiàn)程序里根本沒有刪除緩存的操作,所以這個原因可以排除。
2、寫緩存的方法有問題 -- 這個也可以排除,因為很多地方用這個dll,其它項目不存在這個bug,所以這個原因也可以排除。
3、服務(wù)器上有清除所有內(nèi)存的程序 -- 于是一個個服務(wù)終止了下,最后發(fā)現(xiàn)終止了一個動轉(zhuǎn)靜服務(wù)后,程序就沒有異常了,所以這個問題是因為動轉(zhuǎn)靜服務(wù)引起的了。
解決方案
反編譯了這個動轉(zhuǎn)靜服務(wù)的源碼,發(fā)現(xiàn)并沒有清理內(nèi)存的操作,于是想到了是不是因為動轉(zhuǎn)靜服務(wù)的什么操作,引起了應(yīng)用程序池Appliacation_End,然后cache都被回收了。于是在Global.asax里面的Application_End方法里寫了下面的代碼,用于記錄是否引起了這個事件,以及引起事件觸發(fā)的原因。
protected void Application_End(object sender, EventArgs e)
{
HttpRuntime runtime = (HttpRuntime)typeof(System.Web.HttpRuntime).InvokeMember("_theRuntime",
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField,
null,
null,
null);
if (runtime == null)
return;
string shutDownMessage = (string)runtime.GetType().InvokeMember("_shutDownMessage",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
null,
runtime,
null);
string shutDownStack = (string)runtime.GetType().InvokeMember(
"_shutDownStack",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
null,
runtime,
null);
if (!EventLog.SourceExists(".NETRuntime"))
{
EventLog.CreateEventSource(".NETRuntime", "Application");
}
EventLog log = new EventLog();
log.Source = ".NET Runtime";
log.WriteEntry(String.Format(" _shutDownMessage={0} _shutDownStack={1}", shutDownMessage, shutDownStack), EventLogEntryType.Error);
}
結(jié)果,日志文件里頭果然有記錄,記錄都為:
=====================================================
The description for Event ID ( 0 ) in Source ( .NET Runtime ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event:
_shutDownMessage=Recompilation limit of 15 reached
HostingEnvironment initiated shutdown
HostingEnvironment caused shutdown
_shutDownStack= at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at System.Web.Hosting.HostingEnvironment.InitiateShutdownInternal()
at System.Web.Hosting.HostingEnvironment.InitiateShutdown()
at System.Web.HttpRuntime.ShutdownAppDomain(String stackTrace)
at System.Web.Compilation.DiskBuildResultCache.ShutdownCallBack(Object state)
at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state).
=====================================================
$news_page$
網(wǎng)上搜索了一下導(dǎo)致Asp.Net站點重啟的原因,具體可以參考:,其中第五條就這樣說
修改aspx,master文件不一定會導(dǎo)致重啟;但是每修改一次都會導(dǎo)致一次重新編譯,重新編譯次數(shù)達到15次之后會導(dǎo)致站點重啟,重啟原因是:
Recompilation limit of 15 reached HostingEnvironment initiated shutdown
于是我自己測試了下,停了動轉(zhuǎn)靜服務(wù),在運行的項目里面,進行了如下操作
1、對1個Asp.net文件修改了20次以上,發(fā)現(xiàn)并沒有導(dǎo)致Asp.net站點重啟
2、對15個Asp.net文件進行修改,結(jié)果就出現(xiàn)了Asp.net站點重啟
3、對20個html文件進行修改,發(fā)現(xiàn)并沒有導(dǎo)致Asp.net站點重啟
于是我就納悶了,動轉(zhuǎn)靜導(dǎo)致的都是生成的html文件,并沒有修改動態(tài)文件,為什么會導(dǎo)致站點重啟呢,于是又谷歌了一番,終于又找到個有用的帖子《引起IIS下Asp.net應(yīng)用程序重啟的原因》,這個是翻譯過來的文章,原文是
里面的一條這樣說道,一個文件夾里同時有很多文件發(fā)生改變,.NET系統(tǒng)對這些變化通知來不及反應(yīng),這時候可能會重啟。比如在高PV時每次訪問都生成一次;
仔細想了下,導(dǎo)致我的站點重啟的原因最有可能是兩個
1、一個文件夾里同時有很多文件發(fā)生改變,.NET系統(tǒng)對這些變化通知來不及反應(yīng),這時候可能會重啟。
2、我Asp.net文件里面會include動轉(zhuǎn)靜生成的html文件,可能也被認為是Asp.net文件發(fā)生了變化,這個原因感覺是微乎其微,因為include動轉(zhuǎn)靜生成文件的asp.net文件不止15個,而且我把動轉(zhuǎn)靜的文件個數(shù)控制到15個以內(nèi)的話,居然還是會出現(xiàn)重啟的情況,雖然頻率降低了。
補充(2013.01.18):今天我特地試了一下方法1,對項目下的任意一個文件進行多文件的覆蓋,連續(xù)執(zhí)行n多次,結(jié)果發(fā)現(xiàn)站點果然重啟了。但是好像沒有明顯的規(guī)律,有時候執(zhí)行兩三次就會重啟,有時候20多次照樣不重啟,所以不敢斷言就是文件更新造成的。
$news_page$
下面是微軟的幫助和支持里面的類似問題的原因和解決方案
微軟BUG之多個 ASP.NET 應(yīng)用程序重新啟動出現(xiàn)每隔一至五分鐘
癥狀
很多新的.aspx、.ascx 或.asmx 文件傳播到服務(wù)器,服務(wù)器可能會報告完成后段時間的連續(xù)的應(yīng)用程序重新啟動。此問題可能會顯示幾種不同方式:
為每次重新啟動,重新啟動 ASP.NETApplication 性能計數(shù)器就會增加。
如果使用內(nèi)存中會話狀態(tài),會話變量都將丟失。
應(yīng)用程序狀態(tài)都將丟失。
反復(fù)執(zhí)行Application_Start和Application_End事件。
原因
默認情況下當(dāng)您更新少于 15 個文件在 ASP.NET 中,文件編譯和加載到內(nèi)存中的已編譯文件的舊版本。這是.NET 公共語言運行時命名的并行執(zhí)行的功能。
但是,舊版本的已編譯的代碼保持無限期地使用通過并行執(zhí)行的內(nèi)存中。當(dāng)您更新多個文件 (例如,30 多個文件),如果不重新啟動應(yīng)用程序以清除內(nèi)存中的舊版本時,可能使用過多的內(nèi)存。若要解決此問題,ASP.NET 有一項功能的應(yīng)用程序?qū)⒆詣又匦聠犹囟〝?shù)目的文件更新后。
應(yīng)進行重新啟動,一次只能為已更新的文件的完整列表。重新應(yīng)用程序啟動后,舊版本應(yīng)不駐留在內(nèi)存中。因此,應(yīng)用程序應(yīng)該不需要重新啟動以重新編譯文件的新版本。但是,加載到服務(wù)器 (例如,61 文件) 很多新的.aspx 或.ascx 文件時,將出現(xiàn)此問題。重新服務(wù)器卸載前 15 個文件時編譯應(yīng)用程序和每次重新編譯另一個文件 15 個直到服務(wù)器達到 61。這將導(dǎo)致四個應(yīng)用程序重新啟動,即使只需要其中的。
解決方案
若要避免自動重新啟動基于已更新的文件的數(shù)量,將numRecompilesBeforeAppRestart屬性設(shè)置 Machine.config 文件中默認值為 15 為數(shù)字的大于計劃內(nèi)的應(yīng)用程序重新啟動之間將更新的文件的數(shù)目。如果您將numRecompilesBeforeAppRestart設(shè)置為很多,您可能需要重新啟動應(yīng)用程序手動釋放舊版本的程序集使用的內(nèi)存。
注意: 如果 ASP.NET 消耗太多內(nèi)存,ASP.NET 應(yīng)用程序自動重新啟動。
如果要更新一定數(shù)目的文件,并且如果您想要應(yīng)用程序自動重新啟動,設(shè)置numRecompilesBeforeAppRestart為一個數(shù)字,小于只是將更新的文件的數(shù)目。這將導(dǎo)致較少的內(nèi)存中的舊程序集的單個應(yīng)用程序重新啟動。例如,設(shè)置為numRecompilesBeforeAppRestart ,如下所示:
<compilation debug="false" explicit="true" numRecompilesBeforeAppRestart="50" defaultLanguage="vb">
更多信息請查看IT技術(shù)專欄