理解和配置Out of memory: Kill process
轉(zhuǎn)自:愛開源
理解 OOM killer
最近有位 VPS 客戶抱怨 MySQL 無緣無故掛掉,還有位客戶抱怨 VPS 經(jīng)常死機,登陸到終端看了一下,都是常見的 Out of memory 問題。這通常是因為某時刻應用程序大量請求內(nèi)存導致系統(tǒng)內(nèi)存不足造成的,這通常會觸發(fā) Linux 內(nèi)核里的 Out of Memory (OOM) killer,OOM killer 會殺掉某個進程以騰出內(nèi)存留給系統(tǒng)用,不致于讓系統(tǒng)立刻崩潰。如果檢查相關的日志文件(/var/log/messages)就會看到下面類似的 Out of memory: Kill process 信息:
... Out of memory: Kill process 9682 (mysqld) score 9 or sacrifice child Killed process 9682, UID 27, (mysqld) total-vm:47388kB, anon-rss:3744kB, file-rss:80kB httpd invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0 httpd cpuset=/ mems_allowed=0 Pid: 8911, comm: httpd Not tainted 2.6.32-279.1.1.el6.i686 #1 ... 21556 total pagecache pages 21049 pages in swap cache Swap cache stats: add 12819103, delete 12798054, find 3188096/4634617 Free swap = 0kB Total swap = 524280kB 131071 pages RAM 0 pages HighMem 3673 pages reserved 67960 pages shared 124940 pages non-sharedLinux 內(nèi)核根據(jù)應用程序的要求分配內(nèi)存,通常來說應用程序分配了內(nèi)存但是并沒有實際全部使用,為了提高性能,這部分沒用的內(nèi)存可以留作它用,這部分內(nèi)存是屬于每個進程的,內(nèi)核直接回收利用的話比較麻煩,所以內(nèi)核采用一種過度分配內(nèi)存(over-commit memory)的辦法來間接利用這部分 “空閑” 的內(nèi)存,提高整體內(nèi)存的使用效率。一般來說這樣做沒有問題,但當大多數(shù)應用程序都消耗完自己的內(nèi)存的時候麻煩就來了,因為這些應用程序的內(nèi)存需求加起來超出了物理內(nèi)存(包括 swap)的容量,內(nèi)核(OOM killer)必須殺掉一些進程才能騰出空間保障系統(tǒng)正常運行。用銀行的例子來講可能更容易懂一些,部分人取錢的時候銀行不怕,銀行有足夠的存款應付,當全國人民(或者絕大多數(shù))都取錢而且每個人都想把自己錢取完的時候銀行的麻煩就來了,銀行實際上是沒有這么多錢給大家取的。
內(nèi)核檢測到系統(tǒng)內(nèi)存不足、挑選并殺掉某個進程的過程可以參考內(nèi)核源代碼 linux/mm/oom_kill.c,當系統(tǒng)內(nèi)存不足的時候,out_of_memory() 被觸發(fā),然后調(diào)用 select_bad_process() 選擇一個 “bad” 進程殺掉,如何判斷和選擇一個 “bad” 進程呢,總不能隨機選吧?挑選的過程由 oom_badness() 決定,挑選的算法和想法都很簡單很樸實:最 bad 的那個進程就是那個最占用內(nèi)存的進程。
/*** oom_badness - heuristic function to determine which candidate task to kill* @p: task struct of which task we should calculate* @totalpages: total present RAM allowed for page allocation** The heuristic for determining which task to kill is made to be as simple and* predictable as possible. The goal is to return the highest value for the* task consuming the most memory to avoid subsequent oom failures.*/ unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,const nodemask_t *nodemask, unsigned long totalpages) {long points;long adj;if (oom_unkillable_task(p, memcg, nodemask)) return 0;p = find_lock_task_mm(p);if (!p) return 0;adj = (long)p->signal->oom_score_adj;if (adj == OOM_SCORE_ADJ_MIN) {task_unlock(p); return 0;}/** The baseline for the badness score is the proportion of RAM that each* task's rss, pagetable and swap space use.*/points = get_mm_rss(p->mm) + p->mm->nr_ptes +get_mm_counter(p->mm, MM_SWAPENTS);task_unlock(p);/** Root processes get 3% bonus, just like the __vm_enough_memory()* implementation used by LSMs.*/if (has_capability_noaudit(p, CAP_SYS_ADMIN))adj -= 30;/* Normalize to oom_score_adj units */adj *= totalpages / 1000;points += adj;/** Never return 0 for an eligible task regardless of the root bonus and* oom_score_adj (oom_score_adj can't be OOM_SCORE_ADJ_MIN here).*/ return points > 0 ? points : 1; }理解了這個算法我們就理解了為啥 MySQL 躺著也能中槍了,因為它的體積總是最大(一般來說它在系統(tǒng)上占用內(nèi)存最多),所以如果 Out of Memeory (OOM) 的話總是不幸第一個被 kill 掉。解決這個問題最簡單的辦法就是增加內(nèi)存,或者想辦法優(yōu)化 MySQL 使其占用更少的內(nèi)存,除了優(yōu)化 MySQL 外還可以優(yōu)化系統(tǒng)(優(yōu)化 Debian 5,優(yōu)化 CentOS 5.x),讓系統(tǒng)盡可能使用少的內(nèi)存以便應用程序(如 MySQL) 能使用更多的內(nèi)存,還有一個臨時的辦法就是調(diào)整內(nèi)核參數(shù),讓 MySQL 進程不容易被 OOM killer 發(fā)現(xiàn)。
配置 OOM killer
我們可以通過一些內(nèi)核參數(shù)來調(diào)整 OOM killer 的行為,避免系統(tǒng)在那里不停的殺進程。比如我們可以在觸發(fā) OOM 后立刻觸發(fā) kernel panic,kernel panic 10秒后自動重啟系統(tǒng)。
# sysctl -w vm.panic_on_oom=1 vm.panic_on_oom = 1# sysctl -w kernel.panic=10 kernel.panic = 10# echo "vm.panic_on_oom=1" >> /etc/sysctl.conf # echo "kernel.panic=10" >> /etc/sysctl.conf從上面的 oom_kill.c 代碼里可以看到 oom_badness() 給每個進程打分,根據(jù) points 的高低來決定殺哪個進程,這個 points 可以根據(jù) adj 調(diào)節(jié),root 權限的進程通常被認為很重要,不應該被輕易殺掉,所以打分的時候可以得到 3% 的優(yōu)惠(adj -= 30; 分數(shù)越低越不容易被殺掉)。我們可以在用戶空間通過操作每個進程的 oom_adj 內(nèi)核參數(shù)來決定哪些進程不這么容易被 OOM killer 選中殺掉。比如,如果不想 MySQL 進程被輕易殺掉的話可以找到 MySQL 運行的進程號后,調(diào)整 oom_score_adj 為 -15(注意 points 越小越不容易被殺):
# ps aux | grep mysqld mysql 2196 1.6 2.1 623800 44876 ? Ssl 09:42 0:00 /usr/sbin/mysqld# cat /proc/2196/oom_score_adj 0 # echo -15 > /proc/2196/oom_score_adj當然,如果需要的話可以完全關閉 OOM killer(不推薦用在生產(chǎn)環(huán)境):
# sysctl -w vm.overcommit_memory=2# echo "vm.overcommit_memory=2" >> /etc/sysctl.conf總結
以上是生活随笔為你收集整理的理解和配置Out of memory: Kill process的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Eclipse改字体字号
- 下一篇: Eclipse快捷键归纳及整理