伺服器記憶體太小,傷不起![異常與應用程式集區引發的連鎖命案]

來源:互聯網
上載者:User

最近都在寫 秋色園技術原理解析 文章,今天就寫一篇散文,簡述一下伺服器記憶體太小引發的命案。

 

以前寫文都排版,這篇就當散文了...寫完就這樣了,當然加黑加紅還是給加了。

 

首先,我先上2張秋色園伺服器當前進程及記憶體的圖片:

 

1:進程

 

2:實體記憶體剩餘

 

看完這兩張圖片,啥感覺?記憶體窮緊張!!!!

 

窮緊張不打緊,打緊的是比緊張還緊張的情況發生了,什麼情況?

 

出事故了,應用程式集區要產生回收動作了!!!!

 

先看一下應用程式集區什麼情況會產生回收動作?

 

1:IIS應用程式集區裡的“回收”裡的配置就不說了,這些是你自己定義的。

2:你手動執行“回收”,以重啟應用程式集區。

3:你升級dll到伺服器中,新升的升級會引發應用程式集區重啟。

4:web應用程式產生“錯誤”,進程終止,引發應用程式集區重啟。

5:臨時想不出來......

 

 

出事了,出事了,出啥事了?

 

還不是記憶體窮緊張那點破事,為了示範一下什麼事,我決定回收一下應用程式集區給大夥!!!

 

這裡本機樣本回收了,大夥知道咋回事就可以了,哈哈:

 

看到了吧,兩個進程,這是什麼情況?

IIS啟用了新的進程來接收新的請求,同時舊的進程請求會保留繼續處理之前的請求隊列,直到處理完所有之前的請求才結束。

大體就是這麼一回事了,問題就產生在這一瞬間:

本來就沒記憶體了,舊的進程不回收,新的進程又出來,一出來就喊著要記憶體,可是系統又給不了記憶體,於是就卡在那裡,還造成CPU百分百的情況。

就在這個小間間,網站訪問就卡住了,打不開了,給人一種速度超慢的感覺。

 

什麼時候你感覺開啟了,估計就是舊的進程光榮退休了。

 

好了,升級時候的情況並不多,應用程式集區也設定了半夜才回收一次,理論上回收也不多,這種小瞬間產生的機率並不多。

 

可是網站不穩定的情況才出現的挺頻繁,似乎超出我設定的時候和升級的頻率。

 

就在這些天,我發現我基礎有點差:

web應用程式產生“錯誤”,進程終止,引發應用程式集區重啟。

以前都沒怎麼注意,現在發現了,代碼寫的不好,異常不處理好,應用程式集區就會經常性重啟,也是引發你網站慢的一個原因。

 

給大夥截一張圖:

 

大夥到自己伺服器上看這事件,如果看到一堆錯誤及警告,說明你和我一樣基礎差。

 

這些日誌是怎麼產生的?

 

其實就是系統未被捕獲的異常的,然後最終一路過五關,最後就跑這來了,跑到這來,基本上你的應用程式集區就變的很不穩定的說。

 

下面就隨意扯扯異常這事情

首先一點就是:

在.NET 2.0中,主線程或線程的錯誤,都會導致進程的中止,引發應用程式集區回收。

1.1版本的時候,線程的錯誤是不會引發主進程中止的。

 

PS:還記得我上篇文章“秋色園QBlog技術原理解析:效能最佳化篇:使用者和文章計數器方案(十七)”說到的內建線程吧,

其實隱藏說的就是這問題,線程的存取違規,經常性的引發了主進程中止,導致應用程式集區重啟。

 

再說一點的就:

先把日誌上的警告和異常給處理了。

 

最後一點的就是:

全域捕獲未處理的異常,然後作掉它, 不讓它跑到這來危害應用程式集區重啟 。[補充:作掉它並不能避免應用程式集區重啟]

 

基礎不好,很多天了,才偶然發現這麼點代碼:

一:AppDomain.CurrentDomain.UnhandledException 事件

        public Window1() {
            InitializeComponent();
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        }

        void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            throw new NotImplementedException();
        }

PS:在web中發現這傢伙似乎不起作用,沒深入糾結它,而且它阻止不了異常往上報,只能是收集資訊用。

 

二:HttpApplication.Error事件

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(context_BeginRequest);
            context.Error += new EventHandler(context_Error);
        }

        void context_Error(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;
            Log.WriteLogToTxt(app.Server.GetLastError());
            app.Server.ClearError();//把錯誤消滅了,不讓它往上拋
        }

 

這裡其實要說的就是app.Server.ClearError(),為了發現這一行代碼,我糾結了好多個小時,最後很偶然才發現它,[雖然發現了它,但是作用似乎不大]。

 

補充:

在樓下網友:長河落魄 的疑問聲中,我測試了一下,得到以下結果:

1:主線程中產生的“錯誤”,只要不是致命的,系統日誌中僅是“警告”層級,它不會引發應用程式重啟。

2:內建線程中產生的“錯誤”,系統中產生的“錯誤”層級,它會中止進程,而且,上面的全域語句並不能捕獲到異常。

 

當然,這裡還有幾個疑惑:

1:應用程式集區是不是只遇到“錯誤”層級的,才會引發終止,重啟?

2:主線程中一般的錯誤都是“警告”層級,那有沒有可能會產生“錯誤”層級的錯誤呢?如果產生了,是不是一樣可攔截?這上面的清除異常的代碼,是不是就有效了?

3:多線程中的異常,沒有全域捕獲的事件了?如果有,你在哪呢?

 

 

好了,現在基本上錯誤都被記錄,一步一步對著日誌一個一個消滅了,現在基本上應用程式集區很穩定不亂重啟了,安穩了許多。

 

其實總結還是一句:記憶體太小,傷不起啊!

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.