最近遇到客戶端在往redis中寫入資料的時候發生了一個這樣一個錯誤:
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.
第一次遇到這種錯誤還是蠻好奇的,主要是它無法重現(或必現),只是會偶爾出現,客戶端拋出該例外后redis服務狀態也是正常的,特意查了一下相關的資料,結合當時自己的操作場景,還算是解釋的通的,
該問題的大概原因在于:開啟了snapshot的持久化模式,且在大量寫入的時候bgsave持久化例外,導致客戶端寫入資料失敗,原因譯文中有提及,
當然解決辦法也很簡單,設定引數stop-writes-on-bgsave-error為no,也即bgsave例外的時候不要阻止繼續寫入資料,
筆者的環境是centos 7+ Redis 5.0.1,操作場景是并發執行緒以pipline的方式往redis中寫入資料(作業系統遠大于redis中的資料占用記憶體),某些客戶端會偶發上述錯誤,但是redis服務本身沒有例外,事后可以正常訪問,
經檢查redis的日志和系統日志,均沒有記錄到例外資訊,應該是redis設定了stop-writes-on-bgsave-error=yes的情況下,服務端bgsave失敗之后一種正常的阻止繼續寫入行為,
同時,盡管在作業系統的記憶體充足的情況下,redis的bgsave為什么會失敗,這也是一個需要思考的問題,
這個問題一直沒有查到日志(不管是redis的日志還是系統的日志),一直懷疑是不是自己整錯什么東西了,直至發現這個哥們也提到這個問題:the issue happens intermittently and dont know why. no indication in the logs.

另:redis的bgsave是一個獨立于redis服務的行程,對于在大批量寫入的情況下,經常可以看到一個redis實體下的這個bgsave獨立行程(行程之間是無法共享記憶體的)
以下為譯文,原文地址:https://blog.sakuragawa.moe/debugging-misconf-redis-is-configured-to-save-rdb-snapshots/
有時候Redis會拋出如下的錯誤:
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.
發生此錯誤是因為BGSAVE失敗,很多時候BGSAVE失敗是因為fork無法分配記憶體,很多時候fork無法分配記憶體(盡管機器有足夠的可用RAM),因為作業系統的優化沖突,
Override Error in Redis Configuration
使用redis cli,您可以停止嘗試保存快照:
config set stop-writes-on-bgsave-error no
這是一個快速的解決方法,但是如果您關心使用它的資料,您應該首先檢查一下BGSAVE失敗的原因,
這就暫時解決了這個問題,但是,過度查看這個錯誤是一種可怕的方法,因為這個選項的作用是阻止redis通知寫操作已經停止,并且在不將資料寫入快照的情況下繼續操作,這只是忽略了這個錯誤,
Save Redis on Low Memory
由于記憶體不足,bgsave程序中可能出現錯誤,
發生此錯誤是因為BGSAVE失敗,在BGSAVE期間,Redis fork一個子行程以將資料保存到磁盤上,
雖然BGSAVE失敗的確切原因可以從日志中查看(通常在/var/log/redis/redis-服務器日志但是很多時候BGSAVE失敗是因為fork不能分配記憶體,很多時候fork無法分配記憶體(盡管機器有足夠的可用RAM),因為作業系統的優化沖突,
從Redis常見問題中可以看出:
Background saving is failing with a fork() error under Linux even if I've a lot of free RAM!
Redis后臺保存模式依賴于現代作業系統中fork的copy-on-write語意:Redis forks(創建一個子行程)是父行程的完全副本,子行程將資料庫轉儲到磁盤上,最后退出,
理論上,子行程應該使用與父行程作為副本一樣多的記憶體,但實際上由于大多數現代作業系統實作的“寫時拷貝”語意,父行程和子行程將共享公共記憶體頁,
只有在子級或父級中更改頁時,才會復制該頁,因為理論上,當子行程保存時,所有的頁面都可能會發生變化,所以Linux無法預先知道子行程將占用多少記憶體,因此,如果overcommit_memory設定設定為zero fork,則將失敗,除非有足夠多的可用RAM來真正復制所有父記憶體頁,結果是,如果你有一個3gb的Redis資料集,而只有2gb的空閑記憶體,那么它將失敗,
# echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf # sysctl vm.overcommit_memory=1
Redis不需要作業系統認為的那樣多的記憶體來寫入磁盤,因此可能會先發制人地讓fork失敗,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/209935.html
標籤:NoSQL
