1. 程式人生 > >Redis報錯Can't save in background: fork: Cannot allocate memory及類似問題的處理方法

Redis報錯Can't save in background: fork: Cannot allocate memory及類似問題的處理方法

 問題的發現及解決過程:

1.Redis主從複製(一主一從)環境在客戶端用命令檢視主從狀態

在slave上輸入命令顯示如下:

在master上輸入命令顯示如下:

從顯示可以看出主從關係出現問題,然後檢視slave的redis.log有如下報錯:

以為是IP及埠問題,經檢查後發現非此問題。於是在網上檢視一些別人的解決方法,但試過後都無效。於是檢視master的redis.log有如下報錯:

說明記憶體不足,無法為fork子程序分配記憶體,這就是主從出現問題的原因。

解決方法:

在master上的操作:

vim /etc/sysctl.conf

vm.overcommit_memory = 1  #在檔案裡新增該行後然後執行sysctl -p命令,該行的解釋請看參考連結 https://blog.csdn.net/zqz_zqz/article/details/53384854 或下面的知識點擴充套件

此時再檢視主從關係:

slave顯示:

master顯示:

說明主從關係已經恢復正常,再檢視redis.log發現已經不再報錯。

知識點擴充套件:

1.vm.overcommit_memory 引數說明如下:

Linux對大部分申請記憶體的請求都回復"yes",以便能跑更多更大的程式。因為申請記憶體後,並不會馬上使用記憶體,將這些不會使用的空閒記憶體分配給其它程式使用,以提高記憶體利用率,這種技術叫做Overcommit。一般情況下,當所有程式都不會用到自己申請的所有記憶體時,系統不會出問題,但是如果程式隨著執行,需要的記憶體越來越大,在自己申請的大小範圍內,不斷佔用更多記憶體,直到超出實體記憶體,當linux發現記憶體不足時,會發生OOM killer(OOM=out-of-memory)。它會選擇殺死一些程序(使用者態程序,不是核心執行緒,哪些佔用記憶體越多,執行時間越短的程序越有可能被殺掉),以便釋放記憶體。當oom-killer發生時,linux會選擇殺死哪些程序?選擇程序的函式是oom_badness函式(在mm/oom_kill.c中),該函式會計算每個程序的點數(0~1000)。點數越高,這個程序越有可能被殺死。每個程序的點數跟(/proc/<pid>/oom_adj)oom_score_adj有關,而且oom_score_adj可以被設定(-1000最低,1000最高)。當發生oom killer時,會將記錄在系統日誌/var/log/messages中。

這時候就是記憶體不足,到了這裡,作業系統要怎麼辦,就要祭出我們的主角“overcommit_memory”引數了(/proc/sys/vm/overcommit_memory);

vm.overcommit_memory = 0   啟發策略
比較 此次請求分配的虛擬記憶體大小和系統當前空閒的實體記憶體加上swap,決定是否放行。系統在為應用程序分配虛擬地址空間時,會判斷當前申請的虛擬地址空間大小是否超過剩餘記憶體大小,如果超過,則虛擬地址空間分配失敗。因此,也就是如果程序本身佔用的虛擬地址空間比較大或者剩餘記憶體比較小時,fork、malloc等呼叫可能會失敗。

 vm.overcommit_memory = 1 允許overcommit


直接放行,系統在為應用程序分配虛擬地址空間時,完全不進行限制,這種情況下,避免了fork可能產生的失敗,但由於malloc是先分配虛擬地址空間,而後通過異常陷入核心分配真正的實體記憶體,在記憶體不足的情況下,這相當於完全遮蔽了應用程序對系統記憶體狀態的感知,即malloc總是能成功,一旦記憶體不足,會引起系統OOM殺程序,應用程式對於這種後果是無法預測的。

vm.overcommit_memory = 2 禁止overcommit
根據系統記憶體狀態確定了虛擬地址空間的上限,由於很多情況下,程序的虛擬地址空間佔用遠大於其實際佔用的實體記憶體,這樣一旦記憶體使用量上去以後,對於一些動態產生的程序(需要複製父程序地址空間)則很容易建立失敗,如果業務過程沒有過多的這種動態申請記憶體或者建立子程序,則影響不大,否則會產生比較大的影響 。這種情況下系統所能分配的記憶體不會超過上面提到的CommitLimit大小,如果這麼多資源已經用光,那麼後面任何嘗試申請記憶體的行為都會返回錯誤,這通常意味著此時沒法執行任何新程式。
2./etc/sysctl.conf新增vm.overcommit_memory=1一行相當與修改了/proc/sys/vm/overcommit_memory(預設是0)檔案(參考連結 http://blog.51cto.com/yjw1983/1914916),所以我認為你可以不在/etc/sysctl.conf新增vm.overcommit_memory一行,直接修改/proc/sys/vm/overcommit_memory檔案亦可

3.該問題解決兩天後在slave發現如下報錯:

亦是記憶體不足導致,採用如上方法即可解決

4.此引數是redis優化的一個關鍵引數,如果主從硬體配置相同,建議主從都修改此引數。

5.redis建議根據業務選擇大於redis.conf中auto-aof-rewrite-min-size兩倍的記憶體,例如該值為20G,建議記憶體為64G。auto-aof-rewrite-min-size的大小建議根據持久化檔案的大小來進行優化。