RDB的原理:
在Redis中RDB持久化的觸發分為兩種:自己手動觸發與Redis定時觸發。
針對RDB方式的持久化,手動觸發可以使用:
1):save:會阻塞當前Redis服務器,直到持久化完成,線上應該禁止使用。
2):bgsave:該觸發方式會fork一個子進程,由子進程負責持久化過程,因此阻塞只會發生在fork子進程的時候。
而自動觸發的場景主要是有以下幾點:
1):根據我們的 save m n 配置規則自動觸發;
2):從節點全量復制時,主節點發送rdb文件給從節點完成復制操作,主節點會觸發 bgsave;
3):執行 debug reload 時;
4):執行 shutdown時,如果沒有開啟aof,也會觸發。
由於 save 基本不會被使用到,我們重點看看 bgsave 這個命令是如何完成RDB的持久化的。流程圖如下

1、Redis父進程首先判斷:當前是否在執行save,或bgsave/bgrewriteaof(aof文件重寫命令)的子進程,如果在執行則bgsave命令直接返回。
bgsave/bgrewriteaof 的子進程不能同時執行,主要是基於性能方面的考慮:兩個並發的子進程同時執行大量的磁盤寫操作,可能引起嚴重的性能問題。
2、父進程執行fork操作創建子進程,這個過程中父進程是阻塞的,Redis不能執行來自客戶端的任何命令;
3、父進程fork后,bgsave命令返回”Background saving started”信息並不再阻塞父進程,並可以響應其他命令;
4、子進程創建RDB文件,根據父進程內存快照生成臨時快照文件,完成后對原有文件進行原子替換;
5、子進程發送信號給父進程表示完成,父進程更新統計信息。
AOF的原理:
AOF的整個流程大體來看可以分為兩步,一步是命令的實時寫入(如果是 appendfsync everysec 配置,會有1s損耗),第二步是對aof文件的重寫。
對於增量追加到文件這一步主要的流程是:命令寫入=》追加到aof_buf =》同步到aof磁盤。
那么這里為什么要先寫入buf在同步到磁盤呢?如果實時寫入磁盤會帶來非常高的磁盤IO,影響整體性能。
aof重寫是為了減少aof文件的大小,可以手動或者自動觸發,關於自動觸發的規則請看上面配置部分。
fork的操作也是發生在重寫這一步,也是這里會對主進程產生阻塞。
手動觸發: bgrewriteaof,自動觸發 就是根據配置規則來觸發,當然自動觸發的整體時間還跟Redis的定時任務頻率有關系。
流程圖如下:

對於上圖有四個關鍵點補充一下:
1、在重寫期間,由於主進程依然在響應命令,為了保證最終備份的完整性;因此它依然會寫入舊的AOF file中,如果重寫失敗,能夠保證數據不丟失。
2、為了把重寫期間響應的寫入信息也寫入到新的文件中,因此也會為子進程保留一個buf,防止新寫的file丟失數據。
3、重寫是直接把當前內存的數據生成對應命令,並不需要讀取老的AOF文件進行分析、命令合並。
4、AOF文件直接采用的文本協議,主要是兼容性好、追加方便、可讀性高可認為修改修復。
無論是 RDB 還是 AOF 都是先寫入一個臨時文件,然后通過 rename 完成文件的替換工作。
持久化中恢復數據:
數據的備份、持久化做完了,我們如何從這些持久化文件中恢復數據呢?如果一台服務器上有既有RDB文件,又有AOF文件,該加載誰呢?
其實想要從這些文件中恢復數據,只需要重新啟動Redis即可。
恢復數據流程圖:

啟動時會先檢查AOF文件是否存在,如果不存在就嘗試加載RDB。
那么為什么會優先加載AOF呢?因為AOF保存的數據更完整,通過上面的分析我們知道AOF基本上最多損失1s的數據。
性能與實踐:
通過上面的分析,我們都知道RDB的快照、AOF的重寫都需要fork,這是一個重量級操作,會對Redis造成阻塞。因此為了不影響Redis主進程響應,我們需要盡可能降低阻塞。
1、降低fork的頻率,比如可以手動來觸發RDB生成快照、與AOF重寫;
2、控制Redis最大使用內存,防止fork耗時過長;
3、使用更牛逼的硬件;
4、合理配置Linux的內存分配策略,避免因為物理內存不足導致fork失敗。
在線上我們到底該怎么做?我提供一些自己的實踐經驗。
1、如果Redis中的數據並不是特別敏感或者可以通過其它方式重寫生成數據,可以關閉持久化,如果丟失數據可以通過其它途徑補回;
2、自己制定策略定期檢查Redis的情況,然后可以手動觸發備份、重寫數據;
3、單機如果部署多個實例,要防止多個機器同時運行持久化、重寫操作,防止出現內存、CPU、IO資源競爭,讓持久化變為串行;
4、可以加入主從機器,利用一台從機器進行備份處理,其它機器正常響應客戶端的命令;
5、RDB持久化與AOF持久化可以同時存在,配合使用。
本文的內容主要是運維上的一些注意點,但我們開發者了解到這些知識,在某些時候有助於我們發現詭異的bug。
