今天第二次遇到Redis “MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk”的問題。這個錯誤資訊是Redis用戶端工具在儲存資料時候拋出的異常資訊。
網上查了一下,很多人都是建議“config set stop-writes-on-bgsave-error no”。這樣做其實是不好的,這僅僅是讓程式忽略了這個異常,使得程式能夠繼續往下運行,但實際上資料還是會儲存到硬碟失敗。
上一次遇到這個問題是因為一個程式的Bug造成系統記憶體被耗盡了,後來修複了那個Bug問題就解決了。今天出現問題時查看系統記憶體還有2GB左右,“感覺好像不是記憶體的緣故”(後面發現還是因為記憶體的緣故)。
由於Redis是daemon模式啟動並執行,沒法看到詳細的日誌。修改設定檔設定logfile參數為檔案(預設是stdout,建議以後安裝完畢就修改這個參數為檔案,不然會丟掉很多重要訊息),重啟Redis,查看日誌,看到程式啟動時就有一行警告提示:
“WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.”(警告:過量使用記憶體設定為0。在低記憶體環境下,後台儲存可能失敗。為了修正這個問題,請在/etc/sysctl.conf 添加一項 'vm.overcommit_memory = 1' ,然後重啟(或者運行命令'sysctl vm.overcommit_memory=1' )使其生效。)
當時沒明白意思,就忽略了。再啟動Redis用戶端,程式儲存資料時繼續報“MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk”異常,再查看Redis日誌,看到有這樣的錯誤提示“Can’t save in background: fork: Cannot allocate memory”,這個提示很明顯"Fork進程時記憶體不夠用了。"(還是記憶體的問題)。
通過Google查詢“Can’t save in background: fork: Cannot allocate memory”這個提示,找到瞭解決方法: view plain copy to clipboard print ? // 原文:http://pydelion.com/2013/05/27/redis-cant-save-in-background-fork-cannot-allocate-memory/ If you get this error Can't save in background: fork: Cannot allocate memory it means that your current database is bigger than memory you have. To fix the issue enable vm.overcommit_memory: sysctl vm.overcommit_memory=1 To have if after reboot add this line to /etc/sysctl.cnf: vm.overcommit_memory=1
修改vm.overcommit_memory=1後問題果然解決了。
為什麼系統明明還剩2GB的記憶體,Redis會說記憶體不夠呢。
網上查了一下,有人也遇到類似的問題,並且給出了很好的分析(詳見:http://www.linuxidc.com/Linux/2012-07/66079.htm),簡單地說:Redis在儲存資料到硬碟時為了避免主進程假死,需要Fork一份主進程,然後在Fork進程內完成資料儲存到硬碟的操作,如果主進程使用了4GB的記憶體,Fork子進程的時候需要額外的4GB,此時記憶體就不夠了,Fork失敗,進而資料儲存硬碟也失敗了。