一、RDB持久化模式缺陷
1、問題描述:
并發200路,模擬不斷寫redis,持續4小時后,接口調用開始出現大量失敗,錯誤信息如下:
{"data":{"sendResult":null},"base":{"returncode":"99999","returndesc":"系統異常:MISCONF?Redis?is?configured?to?save?RDB?snapshots,?but?is?currently?not?able?to?persist?on?disk.?Commands?that?may?modify?the?data?set?are?disabled.?Please?check?Redis?logs?for?details?about?the?Error."},"qrybase":{"total":0,"count":0,"start":0}}
2、原因分析:
解讀錯誤信息,以為是磁盤不夠用引起,結果發現磁盤還剩余42%,如下所示:
于是根據錯誤信息提示開啟Redis日志,繼續壓測,接口依然報錯,但可從Redis日志信息中
Can’t save in background: fork: Cannot allocate memory
進程使用內存不當有關,查看Redis主進程占用內存如下:占用近55%*4G內存
具體原因:Redis在保存數據到硬盤時為了避免主進程假死,需要Fork一份主進程,然后在Fork進程內完成數據保存到硬盤的操作,如果主進程使用了2.2GB的內存,Fork子進程的時候需要額外的2.2GB,此時內存就不夠了,Fork失敗,進而數據保存硬盤也失敗了。
3、緩解方案(不能根本解決問題):
3.1 修改redis.conf文件中配置項stop-writes-on-bgsave-error no (默認值為yes),即當bgsave快照操作出錯時停止寫數據到磁盤,這樣后面寫錯做均會失敗,為了不影響后續寫操作,故需將該項值改為no
3.2 修改內核參數(如下3種方式),但需要root權限:
(1) 編輯/etc/sysctl.conf?,改vm.overcommit_memory=1,然后sysctl?-p?使配置文件生效 (2)sysctl?vm.overcommit_memory=1 (3)echo?1?>?/proc/sys/vm/overcommit_memory
二、AOF持久化模式缺陷
1、問題1描述:
Redis主從節點均開啟AOF模式,并發200路,模擬不斷寫Redis,持續15分鐘后,接口調用開始出現大量失敗,且Redis所在的linux虛擬服務器掛起。
接口報錯如下:
{"data":null,"base":{"returndesc":"系統異常","returncode":"999999"},"qrybase":null} Biz(dubbo)接口報錯如下: 2015-06-05?11:28:28.760?[DubboServerHandler-X.X.X.X:20882-thread-173]?ERROR??-?error?while?validate?jedis! redis.clients.jedis.exceptions.JedisConnectionException:?java.net.SocketTimeoutException:?Read?timed?out
原因分析:
從dubbo接口報錯信息來看,是由于接口API操作Redis超時導致。從系統日志和IO監控來看,均說明上述問題是由于IO瓶頸(系統IO過于繁忙)所致,如下所示:
從系統日志也能看出,IO阻塞時間超過了120秒,由于系統安全機制導致機器掛起。
總結
測試結果證明AOF模式存在最明顯缺陷,即訪問壓力大時IO會成為性能瓶頸,進而導致服務不可用。
3、緩解方案(不能根本解決問題)
編輯/etc/sysctl.conf ,添加如下配置:
vm.dirty_background_ratio?=?5 vm.dirty_ratio?=?10
然后sysctl -p 使配置文件生效。
問題2描述:
無論采用AOF模式還是RDB(快照模式),當兩文件(.aof或.rdb)大小超過系統內存80%,Redis進程會被系統Kill掉,導致服務不可用。
總結
上述問題說明我們在使用Redis時需要事先做好系統內存的容量規劃,因為一旦Redis宕掉會導致大量數據丟失且是不可恢復的。
更多redis知識請關注redis入門教程欄目。