如何調整PostgreSQL的 Out-Of-Memory Killer設置


當服務器/進程內存不足時,Linux有兩種方法來處理,第一種是OS(Linux)崩潰,整個系統宕機;第二種是終止使系統耗盡內存的進程(應用程序)。第二種方法的最佳選擇是終止進程,防止OS崩潰。簡而言之,Out-Of-Memory Killer是負責終止應用程序以避免內核崩潰的進程,因為它只殺死應用程序並避免整個操作系統崩潰。讓我們首先討論一下OOM和如何工作以及如何控制它,然后我們將討論OOM Killer如何決定殺死哪個應用程序。

Linux操作系統的主要任務之一是在進程請求內存分配時為其分配內存。在大多數情況下,進程/應用程序將向操作系統請求內存,但它不會使用所請求的所有內存。如果操作系統將內存分配給所有請求內存但不打算使用它的進程,它將很快耗盡內存——系統將崩潰。 為了處理這種情況,操作系統有一個特性,允許操作系統將內存提交給進程,而不需要實際分配內存。只有當進程實際計划使用該內存時,才會進行分配。有時,操作系統可能沒有可用的內存,但它會將這些內存提交給進程,當進程計划使用這些內存時,如果提交的內存可用,操作系統就會分配。這個特性的缺點是,操作系統有時會提交內存,在分配內存的時候沒有可用的內存可以分配,系統會崩潰。OOM在這個場景中扮演着至關重要的角色,它殺死進程以避免內核恐慌。

當你的PostgreSQL進程被終止時,你會在日志文件中看到這樣的消息:

Out of Memory: Killed process 12345 (postgres).

  

當系統內存不足且找不到可用內存空間時,將調用out_of_memory函數。在這種情況下,要使內存可用,它只能做一件事——殺死一個(或多個)進程。 OOM-killer應該立即殺死進程還是等待一段時間?很明顯,當出現out_of_memory時,有時是由於等待IO或等待頁面在磁盤上交換。 因此,必須執行一些檢查,OOM-killer將根據以下檢查決定終止進程。如果下面指定的所有檢查都為真,那么OOM將加入並終止進程。

 

進程的選擇

每當發生內存外故障時,將調用out_of_memory()函數。在其中使用select_bad_process()函數,該函數從badness()函數獲得一個分數。最“糟糕”的進程就是被犧牲的進程。badness()函數在選擇過程時遵循一些規則。

1.首先內核自身需要獲得少量的內存

2.嘗試回收大量的內存

3.不會kill使用少量內存的進程

4.嘗試kill少量的進程

5.一些細致的算法提高了用戶想要殺死的進程的犧牲優先級

 

在所有這些檢查列表之后,OOM killer會檢查分數(oom_score)。將“oom_score”設置到每個進程,然后將該值與內存使用量相乘。具有更大值的進程將有很高的概率被OOM killer終止。與特權用戶關聯的進程分數值較低,被OOM殺死的機會也較少。

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進程的機會。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM