在 Linux 中為 PostgreSQL 設定記憶體不足殺手

在 Linux 中為 PostgreSQL 設定記憶體不足殺手

當Linux中數據庫服務器意外退出時,需要查找原因。 可能有幾個原因。 例如, 信號發生器 — 由於後端服務器中的錯誤而失敗。 但這種情況很少見。 大多數情況下,您只是耗盡了磁盤空間或內存。 如果磁盤空間不足,只有一種方法:釋放空間並重新啟動數據庫。

內存不足殺手

當服務器或進程耗盡內存時,Linux 提供兩種解決方案:使整個系統崩潰或終止消耗內存的進程(應用程序)。 當然,最好終止該進程並避免操作系統崩潰。 簡而言之,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被調用時,是由於等待I/O操作或分頁到磁盤。 因此,OOM Killer 必須首先執行檢查,並根據檢查結果決定需要終止該進程。 如果以下所有檢查都是肯定的,OOM 將終止該過程。

工藝選擇

當內存耗盡時,調用該函數 out_of_memory()。 它有一個功能 select_bad_process(),由函數計算 badness()。 “最差”的流程將成為目標。 功能 badness() 根據一定的規則選擇進程。

  1. 內核本身需要一些最小內存。
  2. 您需要釋放大量內存。
  3. 無需終止使用少量內存的進程。
  4. 有必要完成最少的流程。
  5. 複雜的算法可以增加用戶自己想要完成的流程的完成機會。

完成所有這些檢查後,OOM 檢查分數 (oom_score)。 OOM 分配 oom_score 每個進程,然後將該值乘以內存量。 具有較高值的​​進程更有可能成為 OOM Killer 的受害者。 與 root 用戶關聯的進程得分較低,並且不太可能被強制終止。

postgres=# SELECT pg_backend_pid();
pg_backend_pid 
----------------
    3813
(1 row)

Postgres 進程 ID 是 3813,因此另一個 shell 可以使用此內核選項獲取估計值 oom_score:

vagrant@vagrant:~$ sudo cat /proc/3813/oom_score
2

如果您根本不希望 OOM-Killer 終止進程,還有另一個內核選項: oom_score_adj。 添加較大的負值可減少完成您重視的流程的機會。

sudo echo -100 > /proc/3813/oom_score_adj

設置一個值 oom_score_adj,在服務塊中設置 OOMScoreAdjust:

[Service]
OOMScoreAdjust=-1000

或者使用 oomprotect 在一個團隊中 rcctl.

rcctl set <i>servicename</i> oomprotect -1000

強制終止進程

當一個或多個進程已被選擇時,OOM-Killer 會調用該函數 oom_kill_task()。 該函數向進程發送終止信號。 如果內存不足 oom_kill() 調用此函數向進程發送 SIGKILL 信號。 一條消息被寫入內核日誌。

Out of Memory: Killed process [pid] [name].

如何控制 OOM-Killer

在 Linux 上,您可以啟用和禁用 OOM-Killer(儘管不建議使用後者)。 使用該選項來啟用或禁用 vm.oom-kill。 要在運行時啟用 OOM-Killer,請運行命令 sysctl.

sudo -s sysctl -w vm.oom-kill = 1

要禁用 OOM-Killer,請在同一命令中指定值 0:

sudo -s sysctl -w vm.oom-kill = 0

該命令的結果不會永久保存,只會保存到第一次重新啟動之前。 如果您需要更多持久性,請將此行添加到文件中 /etc/sysctl.conf:

echo vm.oom-kill = 1 >>/etc/sysctl.conf

啟用和禁用的另一種方法是寫入變量 panic_on_oom。 該值始終可以簽入 /proc.

$ cat /proc/sys/vm/panic_on_oom
0

如果將該值設置為0,那麼當內存耗盡時,不會出現內核恐慌。

$ echo 0 > /proc/sys/vm/panic_on_oom

如果將該值設置為1,那麼當內存耗盡時,將會發生內核恐慌。

echo 1 > /proc/sys/vm/panic_on_oom

OOM-Killer 不僅可以打開和關閉。 我們已經說過,Linux 可以為進程保留比可用內存更多的內存,但實際上並不分配它,並且此行為由 Linux 內核參數控制。 該變量負責此操作 vm.overcommit_memory.

您可以為其指定以下值:

0: 內核自行決定是否保留過多的內存。 這是大多數 Linux 版本的默認設置。
1: 內核總是會保留額外的內存。 這是有風險的,因為內存可能會耗盡,因為很可能有一天,進程會要求它們必須執行的操作。
2: 內核不會保留比參數中指定的更多的內存 overcommit_ratio.

在此參數中,您指定允許過度保留的內存百分比。 如果沒有空間,則不會分配內存並且預留將被拒絕。 這是為 PostgreSQL 推薦的最安全的選項。 OOM-Killer 受到另一個元素的影響——交換的能力,這是由變量控制的 cat /proc/sys/vm/swappiness。 這些值告訴內核如何處理分頁。 該值越大,OOM 終止進程的可能性越小,但由於 I/O 操作,這會對數據庫產生負面影響。 反之亦然 - 值越低,OOM-Killer 干擾的可能性越高,但數據庫性能也越高。 默認值為 60,但如果整個數據庫都適合內存,則最好將該值設置為 1。

結果

不要讓 OOM-Killer 中的“殺手”嚇到您。 在這種情況下,殺手將成為你係統的救星。 它“殺死”最糟糕的進程並避免系統崩潰。 為了避免使用 OOM-Killer 來終止 PostgreSQL,請設置為 vm.overcommit_memory 值為 2。這並不能保證 OOM-Killer 不必干預,但會減少強制終止 PostgreSQL 進程的機會。

來源: www.habr.com

添加評論