
當在 Linux 資料庫伺服器意外終止,需要確定原因。可能存在多種原因。例如: 信號發生器 — 由於後端服務器中的錯誤而失敗。 但這種情況很少見。 大多數情況下,您只是耗盡了磁盤空間或內存。 如果磁盤空間不足,只有一種方法:釋放空間並重新啟動數據庫。
內存不足殺手
當你 服務器 或者進程記憶體不足, Linux 記憶體溢位殺手(Out-Of-Memory 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() 根據一定的規則選擇進程。
- 內核本身需要一些最小內存。
- 您需要釋放大量內存。
- 無需終止使用少量內存的進程。
- 有必要完成最少的流程。
- 複雜的算法可以增加用戶自己想要完成的流程的完成機會。
完成所有這些檢查後,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
