Redis持久化機制詳解
一. 持久化的意義
- Redis持久化的意義:主要在於故障恢復。Redis如果僅將數據完全保存在內存中,是無法應對災難性故障的。如果Redis進程突然掛掉,保存在內存中的數據就全沒了,如果沒有持久化,後果不堪設想。使用持久化+定期備份(如備份到雲存儲上)的機制,可以在很大程度上解決Redis故障恢復的問題。這樣即使Redis服務宕機,且磁盤損壞,也可以從雲存儲上拉取備份的數據進行恢復,不會造成數據的全部丟失。
- 從一定意義上來說,Redis的持久化也可以視爲高可用的一部分。因爲如果沒有持久化和數據恢復,一旦Redis宕機,即使重啓,數據也都沒了,這樣大量的請求過來,由於沒有命中緩衝,就會直接打到MySQL上,造成緩存雪崩,這樣一來MySQL很有可能就掛了,整個系統就癱瘓了。如果持久化方案做的很好,即使Redis宕機,也可以快速重啓並恢復數據,重新回到可用狀態。
二. 持久化方式
-
Redis持久化方式
- RDB:每隔一段時間,就會對當前Redis內存中的數據生成一份全量的快照文件。
- AOF:將對數據的操作記錄寫在aof日誌文件中(此時是將數據寫入操作系統的OS Cache中),然後每隔一段時間(可配置,默認1s)調用操作系統的fsync操作,強制將OS Cache刷到磁盤文件中。Redis只會寫一個AOF文件,這樣會導致AOF文件越來越大,當AOF文件膨脹到一定程度時,AOF會進行rewrite操作,基於當前Redis內存中最新的數據,重新構造一個新的更小的AOF文件,然後刪除舊的大AOF文件。
-
持久化相關細節
- 由於內存的大小是一定的,當Redis內存中的數據達到上限時,Redis會基於淘汰算法(默認LRU),自動清除一部分數據。
- 如果同時開啓了RDB和AOF兩種持久化策略,則Redis重啓時,會默認通過AOF文件重新構建數據庫,因爲AOF文件中的數據更爲完整。
-
RDB的優缺點
-
優點
- RDB會生成多個文件,每個文件都代表了當時時刻Redis的全量數據,因此RDB文件十分適合用來做冷備份,可以定時生成備份文件,並保存到安全的雲存儲上。
- 由於進行RDB持久化時,主進程只需fork一個子進程,由子進程來執行RDB文件的IO操作,因此對Redis對外提供服務的影響較小,可以讓Redis保存高性能。而AOF每次都需要寫文件,雖然可以快速寫入OS Cache,但是還是需要一定的時間開銷,肯定比RDB略慢一些。
- 通過RDB文件恢復數據比AOF文件更快。因爲RDB存放的是數據快照,恢復時直接加載到內存中即可。而AOF存放的是指令日誌, 恢復的時候需要重放和執行指令。
綜合以上優點,RDB特別適合用來做冷備份。
-
缺點
- 一般來說,RDB持久化的時間間隔要比AOF更長,因此可能丟失更多的數據。這也是RDB最大的缺點,也因此RDB不適應做第一優先恢復方案。
- RDB在fork子進程來執行文件生成時,如果文件較大,可能會導致對客戶端的服務暫停幾毫秒,甚至幾秒。
-
-
AOF的優缺點
-
優點
- AOF可以更好的維護數據的完整性。一般情況下,AOF的時間間隔是1s,因此最多丟失1s的數據。
- AOF日誌文件以append-only模式寫入,所以沒有任何磁盤尋址的開銷,寫入性能非常高,而且文件不容易破損,即使文件尾部破損,也很容易修復。
- AOF日誌文件即使過大的時候,出現後臺重寫操作,也不會影響客戶端的讀寫。因爲在rewrite log的時候,會對其中的指令進行壓縮,創建出一份需要恢復數據的最小日誌出來。在創建新日誌文件的時候,老的日誌文件還是照常寫入。當新的merge後的日誌文件ready的時候,再交換新老日誌文件即可。
- AOF日誌文件的命令通過人類可讀的方式進行記錄,這個特性非常適合做災難性的誤刪除的緊急恢復。比如某人不小心用flushall命令清空了所有數據,只要這個時候後臺rewrite還沒有發生,那麼就可以立即拷貝AOF文件,將最後一條flushall命令給刪了,然後再將該AOF文件放回去,就可以通過恢復機制,自動恢復所有數據。
-
缺點
-
對於同一份數據來說,AOF日誌文件通常比RDB數據快照文件更大。
-
AOF開啓後,支持的寫QPS會比RDB支持的寫QPS低,因爲AOF一般會配置成每秒fsync一次日誌文件。當然,每秒一次fsync,性能也還是很高的。
如果要保證一條數據都不丟,也是可以的,將AOF的fsync設置成每寫入一條數據,就fsync一次即可。但是這樣會導致Redis的QPS大降,並不建議。
-
以前AOF發生過bug,就是通過AOF記錄的日誌,進行數據恢復的時候,沒有恢復一模一樣的數據出來。所以說,類似AOF這種較爲複雜的基於命令日誌/merge/回放的方式,比基於RDB每次持久化一份完整的數據快照文件的方式,更加脆弱一些,容易有bug。不過AOF爲了避免rewrite過程導致的bug,因此每次rewrite並不是基於舊的指令日誌進行merge的,而是基於當時內存中的數據進行指令的重新構建,這樣健壯性會好很多。
-
唯一的比較大的缺點,其實就是做數據恢復的時候,會比較慢。而且做冷備、定期的備份不太方便,可能要自己手寫複雜的腳本去做。
-
-
-
持久化方案最佳實踐
建議同時開啓AOF和RDB。
- 如果僅僅使用RDB,可能會造成大量數據的丟失。
- 如果僅僅使用AOF,則丟失了RDB冷備份的優勢,僅僅通過AOF恢復數據會比較慢。
- 綜合使用AOF和RDB兩種持久化機制,用AOF來保證數據不丟失,作爲數據恢復的第一選擇; 用RDB來做不同程度的冷備,在AOF文件都丟失或損壞不可用的時候,還可以使用RDB來進行快速的數據恢復。
三. RDB機制
-
RDB配置及命令
RDB機制默認開啓
#每隔60s,如果有超過1000個key發生了變更,那麼就生成一個新的dump.rdb文件,就是當前redis內存中完整的數據快#照,這個操作也被稱之爲snapshotting save 60 1000
快照也可以手動調用save或者bgsave命令,同步或異步執行rdb快照生成。
save可以設置多個,就是多個snapshotting檢查點。每到一個檢查點,就會去check一下,是否有指定的key數量發生了變更,如果有,就生成一個新的dump.rdb文件
-
RDB工作流程
- Redis根據配置的save時間,生成檢查點。每到一個檢查點,就會去check一下,該時間間隔內是否有超過指定數量的key發生了變化。
- 如果有超過指定數量的key發生了變化,則Redis會fork一個子進程。
- 子進程嘗試將數據dump到一個臨時的rdb文件中。
- rdb快照文件生成後,用新的文件替換舊的dump.rdb。
-
一些細節
- 每個Redis進程,同一時刻只會存在一個dump.rdb文件。新生成的快照會將舊的覆蓋。
- 通過redis-cli shutdown這種方式去停掉redis,其實是一種安全退出的模式,redis在退出的時候會將內存中的數據立即生成一份完整的rdb快照。
- 如果Redis意外宕機,且當前時間還未到檢查點,則這段時間內產生的數據並不會持久化到快照文件中,就會丟失數據。可以通過kill -9模擬。
四. AOF機制
-
AOF配置
AOF機制默認關閉,需要手動開啓
#開啓AOF appendonly yes #AOF 的fsync策略 # appendfsync always appendfsync everysec # appendfsync no
-
AOF工作流程
Redis開啓AOF策略後,每接收到一條寫命令,都會將該日誌寫入OS Cache中,然後調用操作系統的fsync()函數將日誌寫入磁盤。Redis提供了三種fsync的時機:
- always:每次寫入一條數據,立即將這個數據對應的寫日誌fsync到磁盤上去,性能非常非常差,吞吐量很低。除非要求確保一條數據都不丟失,否則不建議使用這個配置。
- everysec:每秒將OS Cache中的數據fsync到磁盤。這是默認配置,一般生產環境下也使用此配置,性能有保障,QPS還是可以上萬的。
- no:完全依賴操作系統底層的fsync機制,在Redis層面不可控,可能會造成數據丟失,不建議使用。
-
AOF rewrite機制
Redis內存中的數據是不斷變化的,可能會自動化過期,也可能被手動刪除。而且,由於內存大小的限制,Redis當內存佔用量超過一定值時,會通過淘汰策略清除一部分key。這樣一來,可能導致一些已經在內存中不存在的數據仍然保持在AOF日誌文件中,AOF文件可能會膨脹地很大。因此,Redis提供了AOF rewrite的機制,會在後臺對AOF文件進行重寫,以縮小文件的容量。
Redis 2.4之前,需要手動開發一些腳本,去定時通過BGREWRITEAOF命令去執行AOF rewrite。但是redis 2.4之後,會自動進行rewrite操作。
用戶可以配置rewrite的觸發條件:
#當AOF文件增長到上次的百分之多少時,觸發rewrite auto-aof-rewrite-percentage 100 #執行rewrite所需的最小文件大小 auto-aof-rewrite-min-size 64mb
-
rewrite 執行流程
- Redis fork子進程
- 子進程基於當前Redis內存中的數據,構建日誌,創建一個新的臨時的AOF文件並執行寫入操作。
- Redis主進程會繼續接收客戶端的寫請求,將日誌寫入內存,同時也會寫入舊的AOF文件。
- 子進程寫完新的AOF文件後,主進程會將這段時間內內存中生成的新日誌追加到新的AOF文件中。
- 寫入完成,用新的AOF文件替換舊的。
-
AOF文件的修復
如果Redis在向AOF文件append日誌時,突然宕機,可能會導致AOF文件由於不完整而破損。此時,可以通過redis-check-aof --fix命令來修復破損的AOF文件。redis-check-aof命令會刪除不完整的AOF日誌。
五. AOF和RDB同時工作
- RDB的snapshotting操作和AOF的rewrite操作不會同時執行。
- 如果RDB在執行snapshotting時,用戶執行BGREWRITEAOF命令,那麼等RDB快照生成之後,纔會去執行AOF rewrite。
- 如果dump.rdb文件和appendonly.aof文件同時存在,那麼redis重啓的時候,會優先使用AOF進行數據恢復,因爲其中的日誌更完整。
六. 企業級數據備份方案
RDB非常適合做冷備,每次生成之後,就不會再有修改了。
數據備份的主要目的是出現數據錯誤時進行恢復。
- 通過crontab定時調度腳本去做數據備份。
- 每小時都copy一份rdb的備份,到一個目錄中去,僅僅保留最近48小時的備份。
- 每天都保留一份當日的rdb的備份,到一個目錄中去,僅僅保留最近1個月的備份。
- 每次copy備份的時候,都把太舊的備份給刪了。
- 每天晚上將當前服務器上所有的數據備份,發送一份到遠程的雲服務上去。
七. 企業級數據恢復方案
- 如果是redis進程掛掉,那麼重啓redis進程即可,直接基於AOF日誌文件恢復數據。默認的fsync配置,最多丟失1s的數據。
- 如果是redis進程所在機器掛掉,那麼重啓機器後,嘗試重啓redis進程,直接基於AOF日誌文件進行數據恢復。如果AOF文件有破損,可以通過redis-check-aof腳本進行修復。
- 如果redis當前最新的AOF和RDB文件都出現了丟失/損壞,那麼可以嘗試基於該機器上當前的某個最新的RDB數據副本進行數據恢復。這種情況多爲人爲因素引起,如誤刪數據等。
- 如果當前機器上的所有RDB文件全部損壞,那麼從遠程的雲服務上拉取最新的RDB快照回來恢復數據。
- 如果是發現有重大的數據錯誤,比如某個小時上線的程序一下子將數據全部污染了,數據全錯了,那麼可以選擇某個更早的時間點,對數據進行恢復
八. 補充
- 熱備份 VS 冷備份
- 熱備份:實時備份,服務不停止,數據是最新的。
- 冷備份:週期性備份(如:定時每天凌晨開始備份,備份時服務暫時停止。備份的數據不是最新的。
- 通過RDB文件恢復數據的步驟
- 關閉Redis
- **修改配置文件,禁用掉AOF功能。這一步非常重要。**如果AOF功能處於開啓狀態,則Redis重啓時優先會通過AOF文件恢復數據,即使AOF文件不存在,也會創建一個空的,這樣一來無法通過備份的RDB文件進行數據恢復。
- 將備份的RDB文件拷貝到數據目錄下
- 重啓Redis,驗證數據是否已恢復。
- **通過Redis客戶端熱修改配置,開啓AOF功能,使得AOF和RDB文件中的數據保持一致這一步也很重要。**如果不通過這種方式開啓AOF,而是通過重啓Redis修改配置文件的方式,則又會出現2中的問題,導致數據丟失。
- 修改配置文件,開啓AOF功能,重啓Redis。這樣數據就完全恢復了。