Linux操作系統的主要任務之一是在進程請求內存分配時為其分配內存。在大多數情況下,進程/應用程序將向操作系統請求內存,但它不會使用所請求的所有內存。如果操作系統將內存分配給所有請求內存但不打算使用它的進程,它將很快耗盡內存——系統將崩潰。 為了處理這種情況,操作系統有一個特性,允許操作系統將內存提交給進程,而不需要實際分配內存。只有當進程實際計划使用該內存時,才會進行分配。有時,操作系統可能沒有可用的內存,但它會將這些內存提交給進程,當進程計划使用這些內存時,如果提交的內存可用,操作系統就會分配。這個特性的缺點是,操作系統有時會提交內存,在分配內存的時候沒有可用的內存可以分配,系統會崩潰。OOM在這個場景中扮演着至關重要的角色,它殺死進程以避免內核恐慌。
Out of Memory: Killed process 12345 (postgres).
postgres=# select pg_backend_pid(); pg_backend_pid ---------------- 4845 (1 row) postgres=#
postgresql的進程id是4845,在另外shell中可以看到它的oom_score
# cat /proc/4845/oom_score 0
如果你想你的進程不被oom killer殺掉,可以配置另外一個參數oom_score_adj。設置一個較大的負值,可以減少被kill的機會。
# echo -100 > /proc/4845/oom_score_adj
可以在啟動服務中設置:
#vi /usr/lib/systemd/system/postgresql-10.service # Disable OOM kill on the postmaster [Service] OOMScoreAdjust=-1000
殺死一個進程
當選擇一個或多個進程時,OOM-Killer調用oom_kill_task()函數。這個函數負責向進程發送終止/kill信號。在內存不足的情況下,調用這個函數,它可以向進程發送SIGKILL信號。生成一條內核日志消息。
Out of Memory: Killed process [pid] [name].
如何控制OOM-Killer
linux提供了如何啟動和關閉oom-killer,但是不推薦關閉。內核參數vm.oom-kill被用來開啟和關閉oom-killer。
開啟
sysctl -w vm.oom-kill=1
關閉
sysctl -w vm.oom-kill=0
要想永久生效:
echo vm.oom-kill = 1 >>/etc/sysctl.conf
要開啟或關閉的另一種方法是寫變量panic_on_oom變量。
$ cat /proc/sys/vm/panic_on_oom 0
設置為0表示,內核遇到內存溢出時候不會恐慌
$ echo 0 > /proc/sys/vm/panic_on_oom $ echo 1 > /proc/sys/vm/panic_on_oom
除了啟用和禁用外,還有更多的設置。
正如我們已經提到的那樣,Linux可以通過分配內存而超額分配內存給進程,這種行為可以由Linux內核設置控制。
vm.overcommit_memory是用來控制這種行為的變量。
·0:內核決定是否可以overcommit,這是默認設置
·1:內核總是使用overcommit功能。這是一個冒險的設置
·2:內核支持overcommit功能,但是不能超過overcommit_ratio(所有物理內存和交換空間總和的內存)。
# vi /etc/sysctl.conf vm.overcommit_memory = 2 vm.overcommit_ratio = 90 # overcommit_memory= 2 時生效
影響“oom-killer”的第二個因素是交換分區。這個行為可以通過變量/proc/sys/vm/swappiness來控制。這值指定用於處理頁面交換的內核設置。
這個值越大,終止進程的可能性就越小,但是由於I/O,它會影響數據庫的效率。
控制swappiness的變量的值越小,意味着oom殺手出現的可能性越大,但它也會提高數據庫性能。
默認值是60,但是如果整個數據庫內存適合,那么建議將該值設置為1。
要想避免postgresql發生oom,建議設置vm.overcommit_memory=2。這樣不能百分百避免發生,但是會減少殺死postgresql進程的機會。