詳解Redis的持久化機制

Redis 的數據全部在內存裏,如果突然宕機,數據就會全部丟失,因此必須有一種機制來保證 Redis 的數據不會因爲故障而丟失,這種機制就是 Redis 的持久化機制。

Redis 的持久化機制有兩種,第一種是RDB快照,第二種是 AOF 日誌。快照是一次全量備份,AOF 日誌是連續的增量備份。快照是內存數據的二進制序列化形式,在存儲上非常緊湊,而 AOF 日誌記錄的是內存數據修改的指令記錄文本。

1、RDB快照

RDB快照是某個時間點的一次全量數據備份,是二進制文件,在存儲上非常緊湊。

1.1、 觸發機制

RDB持久化觸發機制分爲:手動觸發自動觸發
手動觸發

save命令:會阻塞當前服務器,直到RDB完成爲止,如果數據量大的話會造成長時間的阻塞,線上環境一般禁止使用
bgsave命令:就是background save,執行bgsave命令時Redis主進程會fork一個子進程來完成RDB的過程,完成後自動結束(操作系統的多進程Copy On Write機制,簡稱COW)。所以Redis主進程阻塞時間只有fork階段的那一下。相對於save,阻塞時間很短。

自動觸發

場景一:配置redis.conf,觸發規則,自動執行

# 當在規定的時間內,Redis發生了寫操作的個數滿足條件,會觸發發生BGSAVE命令。
# save <seconds> <changes>
# 當用戶設置了多個save的選項配置,只要其中任一條滿足,Redis都會觸發一次BGSAVE操作
save 900 1 
save 300 10 
save 60 10000
# 以上配置的含義:900秒之內至少一次寫操作、300秒之內至少發生10次寫操作、
# 60秒之內發生至少10000次寫操作,只要滿足任一條件,均會觸發bgsave

場景二:執行shutdown命令關閉服務器時,如果沒有開啓AOF持久化功能,那麼會自動執行一次bgsave

場景三:主從同步(slave和master建立同步機制)
Redis主從同步

1.2、RDB執行流程

Redis 使用操作系統的多進程 cow(Copy On Write) 機制來實現RDB快照持久化

  1. 執行bgsave命令的時候,Redis主進程會檢查是否有子進程在執行RDB/AOF持久化任務,如果有的話,直接返回
  2. Redis主進程會fork一個子進程來執行執行RDB操作,fork操作會對主進程造成阻塞(影響Redis的讀寫),fork操作完成後會發消息給主進程,從而不再阻塞主進程。(阻塞僅指主進程fork子進程的過程,後續子進程執行操作時不會阻塞)
  3. RDB子進程會根據Redis主進程的內存生成臨時的快照文件,持久化完成後會使用臨時快照文件替換掉原來的RDB文件。(該過程中主進程的讀寫不受影響,但Redis的寫操作不會同步到主進程的主內存中,而是會寫到一個臨時的內存區域作爲一個副本)
  4. 子進程完成RDB持久化後會發消息給主進程,通知RDB持久化完成(將上階段內存副本中的增量寫數據同步到主內存)

1.3、RDB的優缺點

優點

  • RDB文件小,非常適合定時備份,用於災難恢復
  • Redis加載RDB文件的速度比AOF快很多,因爲RDB文件中直接存儲的時內存數據,而AOF文件中存儲的是一條條命令,需要重演命令。

缺點

  • RDB無法做到實時持久化,若在兩次bgsave間宕機,則會丟失區間(分鐘級)的增量數據,不適用於實時性要求較高的場景
  • RDB的cow機制中,fork子進程屬於重量級操作,並且會阻塞redis主進程
  • 存在老版本的Redis不兼容新版本RDB格式文件的問題

2、AOF(append only file)日誌

AOF日誌是持續增量的備份,是基於寫命令存儲的可讀的文本文件。AOF日誌會在持續運行中持續增大,由於Redis重啓過程需要優先加載AOF日誌進行指令重放以恢復數據,恢復時間會無比漫長。所以需要定期進行AOF重寫,對AOF日誌進行瘦身。目前AOF是Redis持久化的主流方式。

2.1、開啓方式

AOF默認是關閉的,通過redis.conf配置文件進行開啓

## 此選項爲aof功能的開關,默認爲“no”,可以通過“yes”來開啓aof功能  
## 只有在“yes”下,aof重寫/文件同步等特性纔會生效  
appendonly yes  
  
## 指定aof文件名稱  
appendfilename appendonly.aof  
  
## 指定aof操作中文件同步策略,有三個合法值:always everysec no,默認爲everysec  
appendfsync everysec  
## 在aof-rewrite期間,appendfsync是否暫緩文件同步,"no"表示“不暫緩”,“yes”表示“暫緩”,默認爲“no”  
no-appendfsync-on-rewrite no  
  
## aof文件rewrite觸發的最小文件尺寸(mb,gb),只有大於此aof文件大於此尺寸是纔會觸發rewrite,默認“64mb”,建議“512mb”  
auto-aof-rewrite-min-size 64mb  
  
## 相對於“上一次”rewrite,本次rewrite觸發時aof文件應該增長的百分比  
## 每一次rewrite之後,redis都會記錄下此時“新aof”文件的大小(例如A)
## aof文件增長到A*(1 + p)之後,觸發下一次rewrite,每一次aof記錄的添加,都會檢測當前aof文件的尺寸。  
auto-aof-rewrite-percentage 100  

AOF是文件操作,對於變更操作比較密集的server,那麼將造成磁盤IO的負荷加重。此外linux對文件操作採取了“延遲寫入”手段,即並非每次write操作都會觸發實際磁盤操作,而是進入了buffer中,當buffer數據達到閥值時觸發實際寫入(也有其他時機),這是linux對文件系統的優化。
Linux 的glibc提供了fsync(int fd)函數可以將指定文件的內容強制從內核緩存刷到磁盤。只要 Redis 進程實時調用 fsync 函數就可以保證 aof 日誌不丟失。但是 fsync 是一個磁盤 IO 操作,它很慢!如果 Redis 執行一條指令就要 fsync 一次,那麼 Redis 高性能的地位就不保了。

因此在上述配置文件中,可觀察到Redis中提供了3中AOF記錄同步選項:

  • always:每一條AOF記錄都立即同步到文件,性能很低,但較爲安全。
  • everysec:每秒同步一次,性能和安全都比較中庸的方式,也是redis推薦的方式。如果遇到物理服務器故障,可能導致最多1秒的AOF記錄丟失。
  • no:Redis永不直接調用文件同步,而是讓操作系統來決定何時同步磁盤。性能較好,但很不安全。

2.2、重寫(rewrite)機制

AOF日誌會在持續運行中持續增大,需要定期進行AOF重寫,對AOF日誌進行瘦身。

AOF Rewrite 雖然是“壓縮”AOF文件的過程,但並非採用“基於原AOF文件”來重寫或壓縮,而是採取了類似RDB快照的方式:基於Copy On Write,全量遍歷內存中數據,然後逐個序列到AOF文件中。因此AOF rewrite能夠正確反應當前內存數據的狀態。

AOF重寫(bgrewriteaof)和RDB快照寫入(bgsave)過程類似,二者都消耗磁盤IO。Redis採取了“schedule”策略:無論是“人工干預”還是系統觸發,快照和重寫需要逐個被執行。

重寫過程中,對於新的變更操作將仍然被寫入到原AOF文件中,同時這些新的變更操作也會被Redis收集起來。當內存中的數據被全部寫入到新的AOF文件之後,收集的新的變更操作也將被一併追加到新的AOF文件中。然後將新AOF文件重命名爲appendonly.aof,使用新AOF文件替換老文件,此後所有的操作都將被寫入新的AOF文件。

2.3、觸發機制

和RDB類似,AOF觸發機制也分爲:手動觸發自動觸發

手動觸發
直接調用bgrewriteaof命令

redis-cli -h ip -p port bgrewriteaof

自動觸發

根據auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數確定自動觸發時機

auto-aof-rewrite-min-size:表示運行AOF重寫時文件最小體積,默認爲64MB(我們線上是512MB)。

auto-aof-rewrite-percentage:代表當前AOF文件空間(aof_current_size)和上一次重寫後AOF文件空間(aof_base_size)的值

自動觸發時機:

(aof_current_size > auto-aof-rewrite-min-size ) &&  (aof_current_size - aof_base_size)  /  aof_base_size  >=  auto-aof-rewrite-percentage

其中aof_current_size和aof_base_size可以在info Persistence統計信息中查看。

2.4、AOF的優缺點

優點
AOF只是追加寫日誌文件,對服務器性能影響較小,速度比RDB要快,消耗的內存較少

缺點

  • AOF方式生成的日誌文件太大,需要不斷AOF重寫,進行瘦身。
  • 即使經過AOF重寫瘦身,由於文件是文本文件,文件體積較大(相比於RDB的二進制文件)。
  • AOF重演命令式的恢復數據,速度顯然比RDB要慢。

3、Redis 4.0 混合持久化

  • 僅使用RDB快照方式恢復數據,由於快照時間粒度較大,時回丟失大量數據。
  • 僅使用AOF重放方式恢復數據,日誌性能相對 rdb 來說要慢。在 Redis 實例很大的情況下,啓動需要花費很長的時間。

Redis 4.0 爲了解決這個問題,帶來了一個新的持久化選項——混合持久化。將 rdb 文件的內容和增量的 AOF 日誌文件存在一起。這裏的 AOF 日誌不再是全量的日誌,而是自持久化開始到持久化結束的這段時間發生的增量 AOF 日誌,通常這部分 AOF 日誌很小。相當於:

  • 大量數據使用粗粒度(時間上)的rdb快照方式,性能高,恢復時間快。
  • 增量數據使用細粒度(時間上)的AOF日誌方式,儘量保證數據的不丟失。

在 Redis 重啓的時候,可以先加載 rdb 的內容,然後再重放增量 AOF 日誌就可以完全替代之前的 AOF 全量文件重放,重啓效率因此大幅得到提升。

混合持久化是最佳方式嗎?
不一定。
首先,混合持久化是Redis 4.0才引入的特性,現在很多 公司可能都還在使用3.x版本。使用不了這一特性。
另外,可以使用下面這種方式。Master使用AOF,Slave使用RDB快照,master需要首先確保數據完整性,它作爲數據備份的第一選擇;slave提供只讀服務或僅作爲備機,它的主要目的就是快速響應客戶端read請求或災切換。

至於具體使用哪種持久化方式,就看大家根據場景選擇。沒有最好,只有最合適。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章