redis丟失數據案例
背景介紹:
我們的一台redis服務器,硬件配置為4核,4G內存。redis持久話方案是RDB。前面幾個月redis使用的
內存在1G左右。在一次重啟之后,redis只恢復了部分數據,這時查看redis.log文件,看到如下錯誤:
[23635] 25 Jul 08:30:54.059 * 10000 changes in 60 seconds. Saving... [23635] 25 Jul 08:30:54.059 # Can't save in background: fork: Cannot allocate memory
這時,想起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' )使其生效。
vm.overcommit_memory不同值說明
- 0:表示檢查是否有足夠的內存可用,如果是,允許分配,如果內存不夠,拒絕該請求,並返回一個錯誤應用程序。
- 1:允許分配超出物理內存加上交換內存的請求
- 2:內核總是返回true
redis的數據會寫機制分為兩種
- 同步回寫save命令,redis主進程直接寫數據到磁盤。當數據量大時,這個命令將阻塞,響應時間長
- 異步回寫bgsave命令,redis主進程fork一個子進程,復制主進成的內存並通過子進程回寫數據到磁盤
由於RDB文件寫的時候fork一個子進程。相當於復制一個內存鏡像。當時系統內存是4G,而redis占用了近3G的內存,因此肯定會報內存無法分配。如果vm.overcommit_memory設置為0,在可用內存不足的情況先,就無法分配新的內存。如果vm.overcommit_memory設置為1,那么redis將使用交換內存。
解決方案:
方法一:修改內核參數vim /etc/sysctl。設置vm.overcommit_memory=1然后執行
方法二:使用交換內存並不是一個完美的方案,最好的辦法就是擴大物理內存。