項(xiàng)目中遇到的問題
排查原因
最近調(diào)試一個(gè)東西,寫了個(gè)監(jiān)控頁(yè)面,發(fā)現(xiàn)自己Cache的數(shù)據(jù)在設(shè)定的過(guò)期時(shí)間遠(yuǎn)遠(yuǎn)還沒有到的時(shí)候就過(guò)期了,于是我著手排查了下出現(xiàn)問題的原因:
1、程序會(huì)刪除緩存 -- 查找了整個(gè)項(xiàng)目,發(fā)現(xiàn)程序里根本沒有刪除緩存的操作,所以這個(gè)原因可以排除。
2、寫緩存的方法有問題 -- 這個(gè)也可以排除,因?yàn)楹芏嗟胤接眠@個(gè)dll,其它項(xiàng)目不存在這個(gè)bug,所以這個(gè)原因也可以排除。
3、服務(wù)器上有清除所有內(nèi)存的程序 -- 于是一個(gè)個(gè)服務(wù)終止了下,最后發(fā)現(xiàn)終止了一個(gè)動(dòng)轉(zhuǎn)靜服務(wù)后,程序就沒有異常了,所以這個(gè)問題是因?yàn)閯?dòng)轉(zhuǎn)靜服務(wù)引起的了。
解決方案
反編譯了這個(gè)動(dòng)轉(zhuǎn)靜服務(wù)的源碼,發(fā)現(xiàn)并沒有清理內(nèi)存的操作,于是想到了是不是因?yàn)閯?dòng)轉(zhuǎn)靜服務(wù)的什么操作,引起了應(yīng)用程序池Appliacation_End,然后cache都被回收了。于是在Global.asax里面的Application_End方法里寫了下面的代碼,用于記錄是否引起了這個(gè)事件,以及引起事件觸發(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站點(diǎn)重啟的原因,具體可以參考:,其中第五條就這樣說(shuō)
修改aspx,master文件不一定會(huì)導(dǎo)致重啟;但是每修改一次都會(huì)導(dǎo)致一次重新編譯,重新編譯次數(shù)達(dá)到15次之后會(huì)導(dǎo)致站點(diǎn)重啟,重啟原因是:
Recompilation limit of 15 reached HostingEnvironment initiated shutdown
于是我自己測(cè)試了下,停了動(dòng)轉(zhuǎn)靜服務(wù),在運(yùn)行的項(xiàng)目里面,進(jìn)行了如下操作
1、對(duì)1個(gè)Asp.net文件修改了20次以上,發(fā)現(xiàn)并沒有導(dǎo)致Asp.net站點(diǎn)重啟
2、對(duì)15個(gè)Asp.net文件進(jìn)行修改,結(jié)果就出現(xiàn)了Asp.net站點(diǎn)重啟
3、對(duì)20個(gè)html文件進(jìn)行修改,發(fā)現(xiàn)并沒有導(dǎo)致Asp.net站點(diǎn)重啟
于是我就納悶了,動(dòng)轉(zhuǎn)靜導(dǎo)致的都是生成的html文件,并沒有修改動(dòng)態(tài)文件,為什么會(huì)導(dǎo)致站點(diǎn)重啟呢,于是又谷歌了一番,終于又找到個(gè)有用的帖子《引起IIS下Asp.net應(yīng)用程序重啟的原因》,這個(gè)是翻譯過(guò)來(lái)的文章,原文是:
里面的一條這樣說(shuō)道,一個(gè)文件夾里同時(shí)有很多文件發(fā)生改變,.NET系統(tǒng)對(duì)這些變化通知來(lái)不及反應(yīng),這時(shí)候可能會(huì)重啟。比如在高PV時(shí)每次訪問都生成一次;
仔細(xì)想了下,導(dǎo)致我的站點(diǎn)重啟的原因最有可能是兩個(gè)
1、一個(gè)文件夾里同時(shí)有很多文件發(fā)生改變,.NET系統(tǒng)對(duì)這些變化通知來(lái)不及反應(yīng),這時(shí)候可能會(huì)重啟。
2、我Asp.net文件里面會(huì)include動(dòng)轉(zhuǎn)靜生成的html文件,可能也被認(rèn)為是Asp.net文件發(fā)生了變化,這個(gè)原因感覺是微乎其微,因?yàn)閕nclude動(dòng)轉(zhuǎn)靜生成文件的asp.net文件不止15個(gè),而且我把動(dòng)轉(zhuǎn)靜的文件個(gè)數(shù)控制到15個(gè)以內(nèi)的話,居然還是會(huì)出現(xiàn)重啟的情況,雖然頻率降低了。
補(bǔ)充(2013.01.18):今天我特地試了一下方法1,對(duì)項(xiàng)目下的任意一個(gè)文件進(jìn)行多文件的覆蓋,連續(xù)執(zhí)行n多次,結(jié)果發(fā)現(xiàn)站點(diǎn)果然重啟了。但是好像沒有明顯的規(guī)律,有時(shí)候執(zhí)行兩三次就會(huì)重啟,有時(shí)候20多次照樣不重啟,所以不敢斷言就是文件更新造成的。
$news_page$
下面是微軟的幫助和支持里面的類似問題的原因和解決方案
微軟BUG之多個(gè) ASP.NET 應(yīng)用程序重新啟動(dòng)出現(xiàn)每隔一至五分鐘
癥狀
很多新的.aspx、.ascx 或.asmx 文件傳播到服務(wù)器,服務(wù)器可能會(huì)報(bào)告完成后段時(shí)間的連續(xù)的應(yīng)用程序重新啟動(dòng)。此問題可能會(huì)顯示幾種不同方式:
為每次重新啟動(dòng),重新啟動(dòng) ASP.NETApplication 性能計(jì)數(shù)器就會(huì)增加。
如果使用內(nèi)存中會(huì)話狀態(tài),會(huì)話變量都將丟失。
應(yīng)用程序狀態(tài)都將丟失。
反復(fù)執(zhí)行Application_Start和Application_End事件。
原因
默認(rèn)情況下當(dāng)您更新少于 15 個(gè)文件在 ASP.NET 中,文件編譯和加載到內(nèi)存中的已編譯文件的舊版本。這是.NET 公共語(yǔ)言運(yùn)行時(shí)命名的并行執(zhí)行的功能。
但是,舊版本的已編譯的代碼保持無(wú)限期地使用通過(guò)并行執(zhí)行的內(nèi)存中。當(dāng)您更新多個(gè)文件 (例如,30 多個(gè)文件),如果不重新啟動(dòng)應(yīng)用程序以清除內(nèi)存中的舊版本時(shí),可能使用過(guò)多的內(nèi)存。若要解決此問題,ASP.NET 有一項(xiàng)功能的應(yīng)用程序?qū)⒆詣?dòng)重新啟動(dòng)特定數(shù)目的文件更新后。
應(yīng)進(jìn)行重新啟動(dòng),一次只能為已更新的文件的完整列表。重新應(yīng)用程序啟動(dòng)后,舊版本應(yīng)不駐留在內(nèi)存中。因此,應(yīng)用程序應(yīng)該不需要重新啟動(dòng)以重新編譯文件的新版本。但是,加載到服務(wù)器 (例如,61 文件) 很多新的.aspx 或.ascx 文件時(shí),將出現(xiàn)此問題。重新服務(wù)器卸載前 15 個(gè)文件時(shí)編譯應(yīng)用程序和每次重新編譯另一個(gè)文件 15 個(gè)直到服務(wù)器達(dá)到 61。這將導(dǎo)致四個(gè)應(yīng)用程序重新啟動(dòng),即使只需要其中的。
解決方案
若要避免自動(dòng)重新啟動(dòng)基于已更新的文件的數(shù)量,將numRecompilesBeforeAppRestart屬性設(shè)置 Machine.config 文件中默認(rèn)值為 15 為數(shù)字的大于計(jì)劃內(nèi)的應(yīng)用程序重新啟動(dòng)之間將更新的文件的數(shù)目。如果您將numRecompilesBeforeAppRestart設(shè)置為很多,您可能需要重新啟動(dòng)應(yīng)用程序手動(dòng)釋放舊版本的程序集使用的內(nèi)存。
注意: 如果 ASP.NET 消耗太多內(nèi)存,ASP.NET 應(yīng)用程序自動(dòng)重新啟動(dòng)。
如果要更新一定數(shù)目的文件,并且如果您想要應(yīng)用程序自動(dòng)重新啟動(dòng),設(shè)置numRecompilesBeforeAppRestart為一個(gè)數(shù)字,小于只是將更新的文件的數(shù)目。這將導(dǎo)致較少的內(nèi)存中的舊程序集的單個(gè)應(yīng)用程序重新啟動(dòng)。例如,設(shè)置為numRecompilesBeforeAppRestart ,如下所示:
<compilation debug="false" explicit="true" numRecompilesBeforeAppRestart="50" defaultLanguage="vb">
更多信息請(qǐng)查看IT技術(shù)專欄