MySQL OOM 系統二 OOM Killer_Mysql

來源:互聯網
上載者:User

這裡就涉及到一個問題,到底Kill掉誰呢?一般稍微瞭解一些Linux核心的同學第一反應是誰用的最多,就Kill掉誰。這當然是Linux核心首先考慮的一種重要因素,但是也不完全是這樣的,我們查一些Linux的核心方面的資料,可以知道其實Kill誰是由/proc/<pid>/oom_score來決定的,這個值每個進程一個,是由Linux核心的oom_badness()函數負責計算的。那下面我們來仔細讀一讀badness()函數。  

在badness()函數的注釋部分,寫明了badness()函數的處理思路:

         1) we lose the minimum amount of work done
         2) we recover a large amount of memory
         3) we don't kill anything innocent of eating tons of memory
         4) we want to kill the minimum amount of processes (one)
         5) we try to kill the process the user expects us to kill, this  algorithm has been meticulously tuned to meet the principle of least surprise ... (be careful when you change it)

總的來說就是Kill掉最小數量的進程來擷取最大數量的記憶體,這與我們Kill掉佔用記憶體最大的進程是吻合的。

        /*
         * The memory size of the process is the basis for the badness.
         */

         points = p->mm->total_vm;

分數的起始是進程實際使用的RAM記憶體,注意這裡不包括SWAP,即OOM Killer只會與進程實際的實體記憶體有關,與Swap是沒有關係的,並且我們可以看到,進程實際使用的實體記憶體越多,分數就越高,分數越高就越容易被犧牲掉。

        /*
         * Processes which fork a lot of child processes are likely
         * a good choice. We add the vmsize of the childs if they
         * have an own mm. This prevents forking servers to flood the
         * machine with an endless amount of childs
         */
          ...
                  if (chld->mm != p->mm && chld->mm)
                        points += chld->mm->total_vm;

這段表示子進程佔用的記憶體都會計算到父進程上。

        s = int_sqrt(cpu_time);
        if (s)
                points /= s;
        s = int_sqrt(int_sqrt(run_time));
        if (s)
                points /= s;

 這表明進程佔用的CPU時間越長或者進程啟動並執行時間越長,分數越低,越不容易被Kill掉。

       /*
        * Niced processes are most likely less important, so double
        * their badness points.
        */
        if (task_nice(p) > 0)
                points *= 2;

          如果進程優先順序低(nice值,正值低優先順序,負值高優先順序),則Point翻倍。

       /*
        * Superuser processes are usually more important, so we make it
        * less likely that we kill those.
        */
        if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN) ||
                                p->uid == 0 || p->euid == 0)
                points /= 4;

          super使用者的進程優先順序較低。

        /*
         * We don't want to kill a process with direct hardware access.
         * Not only could that mess up the hardware, but usually users
         * tend to only have this flag set on applications they think
         * of as important.
         */
        if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO))
                points /= 4;

          直接可以訪問原始裝置的進程優先順序較高。

        /*
         * Adjust the score by oomkilladj.
         */
        if (p->oomkilladj) {
                if (p->oomkilladj > 0)
                        points <<= p->oomkilladj;
                else
                        points >>= -(p->oomkilladj);

        }

每個進程有個oomkilladj 可以設定該進程被kill的優先順序,這個參數看上去對Point影響還是比較大的,oomkilladj 最大+15,最小是-17,越大越容易被幹掉,這個值由於是移位元運算,所以影響還是比較大的。

下面我寫個小程式實驗一下:

 #define MEGABYTE 1024*1024*1024 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, char *argv[]){void *myblock = NULL;myblock = (void *) malloc(MEGABYTE);printf("Currently allocating 1GB\n");sleep(1);int count = 0;while( count < 10){ memset(myblock,1,100*1024*1024); myblock = myblock + 100*1024*1024; count++; printf("Currently allocating %d00 MB\n",count); sleep(10);  }  exit(0); }

上面的程式先申請一個1G的記憶體空間,然後100M為單位,填充這些記憶體空間。在一個2G記憶體,400M Swap空間的機器上跑3個上面的進程。我們看一下運行結果:

   

     test1、test2、test3分別申請了1G的虛擬記憶體空間(VIRT),然後每隔10s,實際佔用的RAM空間就增長100M(RES)。

    

    當實體記憶體空間不足時,OS開始進行Swap,可用的Swap空間開始減少。

   
    

     當記憶體是在沒有可分配的空間時,test1進程被作業系統Kill掉了。dmesg 我們可以看到,test1進程被OS Kill掉,同時oom_score為1000。

     這3個進程的oom_adj全部都是預設值0。下面我們來實驗一下設定了oom_adj的效果。重新啟動3個進程,然後我們看到test2的PID是12640

       

   我們運行一下下面的語句

   echo 15 > /proc/12640/oom_adj

  一段時間後,我們看到Swap空間急劇減少,基本上OS OOM_Killer要開動了。 

   

     果然,不出意料,12640進程被kill掉了。

     所以為了避免自己需要的進程被kill掉,可以通過設定進程的oom_adj來實現。當然,有的人會說,這一切都是超售引起的,既然Linux提供了overcommit_memory可以禁用overcommit特性,那為什麼不禁用呢。這有利也有弊,一旦禁用overcommit,就意味著MySQL根本無法申請超過實際記憶體的空間,而在MySQL中,存在很多動態申請記憶體空間的地方,如果申請不到,MySQL就會Crash,這大大增加了MySQL宕機的風險,這也是Linux為什麼要overcommit的原因。

      有了上面的分析,我們不難看出,如果在不設定oom_adj的前提下,MySQL一般都會成為OOM_Killer的首選對象,因為MySQL一般都是記憶體的最大佔用者。那作為MySQL,我們如何盡量的去規避被Kill的風險呢,下一章我們將重點從MySQL的角度分析如何規避OOM。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.