前言
Redis的數據正常都是存儲在內存內,如果宕機突然發生,數據就會全部丟失,因此需要提供一種方式保證redis的數據不會因為故障而丟失,這種機制就是redis的持久化機制。
redis的持久化機制分為:
快照 snapshot模式 全量模式
快照,是一次全量的備份,是內存數據二進制序列化形式,在存儲上非常緊湊
AOF日誌模式 增量模式
AOF日誌是連續的增量備份,長期運行過程中,會變得無比龐大,而且,如果發生宕機,需要讀取所有的日誌文件,進行恢復,需要大量的時間,所以需要定期對AOF重寫,瘦身日誌文件
快照原理
正如我們之前,聊過的,redis是一款單線程程序,該線程要同時負責多個客戶端的併發讀寫操作和內存數據結構的邏輯讀寫。
在服務線上請求的同時,Redis需要進行內存快照,內存快照要求Redis必須進行文件IO操作,因為是單線程,所以文件IO操作就不能使用多路複用API。
意味著,Redis在進行完成服務線上請求的同時,還要進行文件IO操作,會嚴重影響服務器的性能,
同時,Redis不能阻塞客戶端的請求,導致線上業務不可用,那麼Redis就需要一邊持久化,一邊進行響應客戶端請求。
針對以上問題難點,Redis採用多線程COW(Copy On write)機制來實現快照持久化。
fork(多線程)
Redis是有狀態的節點,每次客戶端請求服務端對數據的寫操作,都會觸發狀態的改變。基於全量模式的持久化,通過在狀態改變的瞬間,觸發snapshot進行保存。
Redis的全量寫入包含兩種方式:SAVE BGSAVE
save可以通過客戶端顯式觸發,也可以在redis shutdown時觸發,save本身通過redis命令,單線程串行化執行保存。阻塞其他的操作。
bgsave可以通過客戶端顯式觸發,也可以通過定時任務觸發,也可以在主從模式下,由從節點觸發。
對於bgsave,redis在持久化時,調用glibc函數fork產生一個子進程,快照持久化,完全交給子進程處理,父進程繼續處理客戶端請求。
子進程做數據持久化,不會修改現有的內存數據結構,只是對數據結構進行遍歷讀取,序列化,寫入到磁盤中。
相比save,bgsave不會影響父進程執行處理客戶端請求,但是產生子進程,增加服務器內存的開銷。產生fork進程,會造成在複製父進程中,存在秒級的不可用
AOF原理
在Redis中,增量持久化稱為AOF(Append-only file)方式。Redis僅對數據的變化進行存儲,類似於日誌文件。
AOF日誌文件存儲的是Redis服務器的順序指令序列,AOF日誌只記錄內存改變的指令。
Redis的增量持久化,存在於每次處理完寫命令之後,通過propagate函數觸發。
Redis的AOF包含三種同步策略:
always 每次執行完命令,直接同步觸發fsync方法,強制數據落地磁盤。會降低redis的吞吐量,每次當落地成功,才響應給客戶端,因此此種方式,很大程度的有很好的容錯能力
every second 每秒異步觸發一次fsync方法。
no 不顯式調用fsync方法,由操作系統決定什麼時候落地。
對於Redis數據的回放,即對數據的重寫,全量和增量,觸發時機一致。
Redis 4.0 混合持久化
重啟redis時,很少使用rdb即快照方式進行恢復數據,因為會丟失大量數據,通常採用AOF才進行重放。但是AOF日積月累會很龐大,因此會花費很長時間進行重放。
Redis 4.0為解決上述問題,採用混合持久化。在重啟redis時,進行先加載rdb內容,然後重放增量AOF文件,此時,重啟效率會優化很多。
更多的,可以參考下官方介紹。