今天第二次遇到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進程時內存不夠用了!"(還是內存的問題)。
通過谷歌查詢“Can’t save in background: fork: Cannot allocate memory”這個提示,找到了解決方法:
- // 原文: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失敗,進而數據保存硬盤也失敗了。