Redis的三種持久化策略及選取建議

2023-05-15 12:03:41

概述

Redis是一個基於記憶體的高效能的鍵值型資料庫,它支援三種不同的持久化策略:RDB(快照)、AOF(追加檔案)、混合。這三種策略各有優缺點,需要根據不同的場景和需求進行選擇和設定。本文將介紹這三種策略

RDB(快照)

概述

RDB持久化策略是指在一定的時間間隔內,將Redis記憶體中的資料以二進位制檔案的形式儲存到硬碟上。這個二進位制檔案就是一個快照,它記錄了某個時刻Redis記憶體中的所有資料。RDB持久化策略可以通過組態檔或者命令來觸發,組態檔中可以設定多個條件,當任意一個條件滿足時,就會執行一次快照操作。如下所示:

save 900 1 # 900秒內執行一次 set 操作 則持久化1次
save 300 10 # 300秒內執行10次 set 操作,則持久化1次
save 60 10000 # 60秒內執行10000次 set 操作,則持久化1次

命令有兩種:

  • save:不建議使用,會阻塞redis服務的程序,直到成功建立RDB檔案
  • bgsave:父程序建立一個子程序生成RDB檔案,父程序可以正常處理使用者端的指令,不影響主程序的服務

優缺點

RDB持久化策略的優點有:

  • RDB檔案是一個緊湊的二進位制檔案,佔用空間小,傳輸速度快,適合做備份和災難恢復
  • RDB檔案恢復資料的速度比AOF快,因為只需要載入一次檔案即可
  • RDB持久化對Redis伺服器的效能影響較小,因為大部分工作由子程序完成

RDB持久化策略的缺點有:

  • RDB檔案不能實時或者近實時地反映Redis記憶體中的資料,因為它是定時觸發的。如果在兩次快照之間發生故障,可能會丟失一部分資料
  • RDB檔案在生成過程中可能會佔用較多的記憶體和CPU資源,因為需要複製主程序的記憶體並執行壓縮操作

AOF(追加檔案)

概述

AOF持久化策略是指將Redis伺服器執行的每一條寫命令都記錄到一個文字檔案中,這個文字檔案就是一個追加檔案(append only file)

AOF有三種持久化策略,也就是刷盤策略。可以根據不同的場景使用不同的刷盤策略

然而隨著時間的推移,AOF檔案也會越來越大,因為它記錄了所有的寫命令。這樣會導致AOF檔案佔用過多的磁碟空間,以及恢復資料的時間過長。為了解決這個問題,Redis提供了AOF重寫機制,來壓縮和優化AOF檔案。

優缺點

AOF持久化策略的優點有:

  • AOF檔案可以實時或者近實時地記錄Redis記憶體中的資料,因為它是每次寫命令或者每秒鐘同步一次。如果在同步之間發生故障,可能會丟失一部分資料,但是資料丟失的概率比RDB小。
  • AOF檔案是一個文字檔案,可以方便地檢視和編輯。AOF檔案中的命令是Redis協定格式的,可以直接用Redis使用者端來執行。
  • AOF檔案可以自動進行重寫,以減少冗餘命令和檔案體積。重寫過程不影響Redis伺服器的正常服務,也不會丟失任何資料。

AOF持久化策略的缺點有:

  • AOF檔案通常比RDB檔案大,佔用更多的磁碟空間
  • AOF檔案恢復資料的速度比RDB慢,因為需要重新執行所有的命令
  • AOF檔案在寫入過程中可能會出現資料不一致的情況,例如命令只寫入了一半或者寫入了錯誤的命令。這種情況下需要用redis-check-aof工具來修復AOF檔案

AOF刷盤策略

當Redis重啟時,可以通過重新執行追加檔案中的命令來恢復資料。AOF持久化策略可以通過組態檔來開啟和設定,它決定了寫命令記錄到AOF檔案的頻率。有三個選項:

  • no:寫入快取,什麼時候刷盤由redis決定
  • everysec:每隔一秒刷一次盤
  • always:寫入快取時同時寫入磁碟(儘快刷盤,而不是實時刷盤)

以下是三個策略的對比:

型別 資料安全性 效能
no
everysec 較高 較高
always

AOF重寫

AOF重寫機制的原理是:Redis會建立一個新的AOF檔案,然後根據記憶體中的當前資料狀態,生成相應的寫命令,並寫入到新的AOF檔案中。這樣新的AOF檔案就只包含了最終資料的寫命令,而不包含任何無效或者冗餘的命令。例如:

# 原始AOF檔案
set a 1
set b 2
incr a
del b
set c 3

# 重寫後的AOF檔案
set a 2
set c 3

上圖就是重寫前和重寫後的檔案對比,因為AOF是追加的,是順序讀寫(ES也是這樣的),所以重寫後的命令set a 1incr a變成為set a 2。為了保證在AOF重寫期間的新資料不丟失,Redis中引入了AOF重寫緩衝區。當開始執行AOF檔案重寫之後又接收到使用者端的請求命令,不但要將命令寫入原本的AOF緩衝區(根據上面提到的引數刷盤),還要同時寫入AOF重寫緩衝區:

一旦子程序完成了AOF檔案的重寫,此時會向父程序發出訊號,父程序收到訊號之後會進行阻塞(阻塞期間不執行任何命令),並進行以下兩項工作:

  • AOF重寫緩衝區的檔案重新整理到新的AOF檔案內
  • 將新AOF檔案進行改名並原子操作的替換掉舊的AOF檔案

隨後,在完成了上面的兩項工作之後,整個AOF重寫工作完成,父程序開始正常接收命令。

  • 自動觸發:自動觸發可以通過以下引數進行設定。
# 檔案大小超過上次AOF重寫之後的檔案的百分比。預設100
# 也就是預設達到上一次AOF重寫檔案的2倍之後會再次觸發AOF重寫
auto-aof-rewrite-percentage 100
# 設定允許重寫的最小AOF檔案大小,預設是64M
# 主要是避免滿足了上面的百分比,但是檔案還是很小的情況。
auto-aof-rewrite-min-size 64mb
  • 手動觸發:執行bgrewriteaof命令。

選取正確的持久化策略

Redis現有的持久化策略有三種:

  • AOF
  • RDB
  • AOF與RDB混合

他們各有優缺點,需要結合不同的應用場景綜合考慮,首先先講解AOFRDB的選擇,再講解混合模式

AOF和RDB的選擇

在Redis中,AOF和RDB兩種持久化方式各有優缺點,一般來說,有以下幾個方面需要參考:

  • 資料安全性:如果要求資料不丟失,推薦AOF
    • AOF可以採取每秒同步一次資料或每次寫操作都同步用來保證資料安全性
      • 如果使用每秒同步一次策略,則最多丟失一秒的資料
      • 如果使用每次寫操作都同步策略,安全性達到了極致,但這會影響效能
    • RDB是一個全量的二進位制檔案,恢復時只需要載入到記憶體即可,但是可能會丟失最近幾分鐘的資料(取決於RDB持久化策略)
  • 資料恢復速度:如果要求快速恢復資料,推薦RDB
    • AOF需要重新執行所有的寫命令,恢復時間會更長
    • RDB是一個全量的二進位制檔案,恢復時只需要載入到記憶體即可
  • 資料備份和遷移:如果要求方便地進行資料備份和遷移,推薦RDB
    • AOF檔案可能會很大,傳輸速度慢
    • RDB檔案是一個緊湊的二進位制檔案,佔用空間小,傳輸速度快
  • 資料可讀性:如果要求能夠方便地檢視和修改資料,推薦AOF
    • AOF是一個可讀的文字檔案,記錄了所有的寫命令,可以用於災難恢復或者資料分析
    • RDB是一個二進位制檔案,不易檢視和修改
資料安全性 資料恢復速度 資料備份和遷移 資料可讀性
AOF
RDB

AOF與RDB的混合模式

綜合上一節,我們可以根據不同的場景和需求來選擇合適的持久化方式。但是,在實際應用中,並不一定要二選一,也可以同時使用AOF和RDB兩種持久化方式。這樣可以利用AOF來保證資料不丟失,作為資料恢復的第一選擇;用RDB做不同程度的冷備份,當AOF備份檔案丟失或損壞不可用時,可以使用RDB快照檔案快速地恢復資料

綜上所述,混合模式兼併了RDB重啟後的快速恢復能力和AOF丟失資料風險低的能力,具體操作流程如下:

  1. 子程序會通過BGSAVE 寫入AOF中
  2. 觸發BGREWRITEAOF後,會將AOF寫入到檔案
  3. 將含有RDB和AOF的資料覆蓋舊的AOF檔案(這時AOF檔案一半為RDB,一半為AOF)

混合模式的AOF檔案:

REDIS0008?redis-ver4.0.1?redis-bits繞?ctime聮~`?used-mem?? ?aof-preamble??repl-id(6c3378899b63bc4ebeaafaa09c27902d514eeb1f?repl-offset??? list1?77   /   appleorangegrape?e k1v1彝髖S[zb*2
$6
SELECT
$1
0
*3
$4
sadd
$8
gamedisk
$4
nioh
*3
$4
sadd
$8
gamedisk
$4
tomb

如果想要開啟混合模式,在redis.conf中設定:

aof-use-rdb-preamble yes

同時使用AOF和RDB兩種持久化方式也需要注意一些問題:

  • AOF重寫和RDB持久化可能會同時發生衝突,導致記憶體、CPU和磁碟的消耗增加。為了解決這個問題,Redis採用了一些策略來協調兩者之間的關係。具體可以參考下面的介紹(AOF重寫和RDB持久化的衝突
  • AOF檔案可能會變得很大,導致磁碟空間不足或者恢復時間過長。為了解決這個問題,Redis提供了AOF重寫機制來壓縮AOF檔案。具體可以參考上一節(AOF重寫
  • AOF檔案可能會被損壞或者丟失,導致資料無法恢復。為了解決這個問題,Redis提供了AOF校驗機制來檢測AOF檔案是否完整。具體可以參考下面的介紹(AOF校驗機制

AOF重寫和RDB持久化的衝突

在Redis中,AOF重寫和RDB持久化可能會同時發生,這會導致一些衝突和問題。例如:

  • AOF重寫和RDB持久化都需要fork子程序,如果兩個子程序同時存在,會增加記憶體的消耗和系統的負載。
  • AOF重寫和RDB持久化都需要寫入磁碟,如果兩個檔案同時寫入,會增加磁碟的壓力和IO的開銷。
  • AOF重寫和RDB持久化都需要在完成後通知主程序,如果兩個訊號同時到達,可能會造成訊號丟失或者處理錯誤。

為了解決這些衝突和問題,Redis採用了以下策略:

  • 如果AOF重寫和RDB持久化同時被觸發,那麼只有一個子程序會被建立,優先執行RDB持久化,然後再執行AOF重寫。這樣可以避免同時存在兩個子程序的情況。
  • 如果AOF重寫正在進行,而此時又收到了RDB持久化的請求,那麼RDB持久化會被延遲到AOF重寫完成後再執行。這樣可以避免同時寫入兩個檔案的情況。
  • 如果AOF重寫和RDB持久化都完成了,那麼主程序會先處理RDB持久化的訊號,然後再處理AOF重寫的訊號。這樣可以避免訊號丟失或者處理錯誤的情況。

總之,Redis通過優先順序、延遲和順序等方式來協調AOF重寫和RDB持久化的衝突和問題,保證了資料的完整性和一致性,下圖為簡要說明。

場景 策略
AOF重寫與RDB持久化同時被觸發 優先RDB
AOF重寫正在進行 優先AOF
AOF重寫和RDB持久化都完成 優先RDB

AOF校驗機制

AOF校驗機制是指在Redis啟動時,對AOF檔案進行檢查,判斷檔案是否完整,是否有損壞或者丟失的資料。如果發現AOF檔案有問題,Redis會拒絕啟動,並給出相應的錯誤資訊

AOF校驗機制的原理是使用一個64位元的校驗和(checksum)來對AOF檔案進行驗證。校驗和是一個數位,它是根據AOF檔案的內容計算出來的,如果AOF檔案的內容發生了任何改變,那麼校驗和也會發生變化。因此,通過比較計算出來的校驗和和儲存在AOF檔案末尾的校驗和,就可以判斷AOF檔案是否完整。

具體來說,AOF校驗機制的過程如下:

  • 當Redis執行AOF重寫時,它會在新的AOF檔案末尾寫入一個特殊的命令:*1\r\n$6\r\nCHECKSUM\r\n,這個命令表示接下來要寫入一個校驗和
  • Redis會使用CRC64演演算法,對新的AOF檔案中除了最後一行之外的所有內容進行計算,得到一個64位元的數位作為校驗和,並將這個數位以16進位制的形式寫入到新的AOF檔案末尾。
  • Redis會將新的AOF檔案替換舊的AOF檔案,並將校驗和儲存在記憶體中
  • 當Redis重啟時,它會讀取AOF檔案,並使用同樣的CRC64演演算法,對除了最後一行之外的所有內容進行計算,得到一個64位元的數位作為校驗和,並將這個數位與記憶體中儲存的校驗和進行比較
  • 如果兩個校驗和相同,說明AOF檔案沒有損壞或者丟失資料,Redis會繼續啟動並載入AOF檔案中的資料
  • 如果兩個校驗和不同,說明AOF檔案有問題,Redis會拒絕啟動,並給出類似於Bad file format reading the append only file: checksum mismatch這樣的錯誤資訊

通過這種方式,Redis可以保證在啟動時檢測到AOF檔案是否完整,從而避免載入錯誤或者不完整的資料。當然,這種機制也有一些侷限性:

  • AOF校驗機制只能在Redis啟動時執行,如果在執行過程中AOF檔案被修改或者損壞,Redis無法及時發現
  • AOF校驗機制只能檢測到AOF檔案是否完整,但不能檢測到AOF檔案是否正確。比如說,如果有人惡意地修改了AOF檔案中的某些命令或者引數,導致資料邏輯上出現錯誤,那麼Redis無法識別出這種情況。
  • AOF校驗機制會增加Redis啟動時的時間開銷,因為需要對整個AOF檔案進行計算。如果AOF檔案很大,那麼這個過程可能會很慢。

總之,AOF校驗機制是一種簡單而有效的方法,可以保證在Redis啟動時檢測到AOF檔案是否完整。但是它也有一些侷限性和代價,需要在實際應用中權衡利弊。

三種模式的選擇建議

具體的選擇建議如下:

  • 如果對資料完整性要求不高,可以只使用RDB,或者將AOF的同步頻率設定為每秒一次
  • 如果想讓資料儘可能不丟失,可以只使用AOF,並將AOF的同步頻率設定為每次寫入操作都同步
  • 如果對資料完整性和效能都有要求,可以同時使用AOF和RDB,並將AOF的同步頻率設定為每秒一次。這樣既可以保證資料的安全性,又可以利用RDB進行快速的資料恢復
  • 如果既想節省磁碟空間,又想提高資料恢復速度,可以只使用RDB,並適當調整RDB的快照頻率

這三種模式各有優缺點,需要根據具體的場景和需求來進行選擇和設定。在選擇時,需要考慮以下幾個因素:

  • 資料完整性:即資料丟失的風險和可接受的範圍
  • 資料恢復速度:即從持久化檔案恢復到記憶體中所需的時間
  • 磁碟空間佔用:即持久化檔案所佔用的磁碟空間大小
  • 寫入效能:即持久化操作對Redis伺服器端的寫入效能的影響

注意:
AOF策略設定為 always 或 everysec,並且BGSAVE BGREWRITEAOF正在對磁碟執行大量 I/O 時,Redis 刷盤可能會阻塞
可以設定no-appendfsync-on-rewrite yes,來緩解這個問題。這樣的話,當另一個子程序正在儲存的時候,Redis 的永續性與appendfsync no相同。實際上,最嚴重的情況是丟失30秒的紀錄檔

持久化策略常見問題及解決方案

AOF檔案過大

當AOF檔案過大時,會佔用磁碟空間,影響寫入效能,甚至導致Redis啟動失敗。可以使用bgrewriteaof命令或者設定auto-aof-rewrite-percentageauto-aof-rewrite-min-size引數來觸發AOF重寫操作,將AOF檔案壓縮為最小的命令集合

# 檔案大小超過上次AOF重寫之後的檔案的百分比。預設100
# 也就是預設達到上一次AOF重寫檔案的2倍之後會再次觸發AOF重寫
auto-aof-rewrite-percentage 100
# 設定允許重寫的最小AOF檔案大小,預設是64M
# 主要是避免滿足了上面的百分比,但是檔案還是很小的情況。
auto-aof-rewrite-min-size 64mb

AOF檔案損壞

當AOF檔案損壞時,會導致Redis無法正常啟動或者恢復資料。可以使用redis-check-aof工具來修復AOF檔案,或者使用備份的RDB檔案來恢復資料

AOF 檔案可能會被截斷

在 Redis 啟動過程中,當 AOF 資料被載入回記憶體時,可能會發現 AOF 檔案在最後被截斷

  • aof-load-truncated yes,則載入截斷的 AOF 檔案,並且記錄紀錄檔
  • aof-load-truncated no,則伺服器會因錯誤拒絕啟動,且需要在啟動伺服器之前使用redis-check-aof修復aof檔案

可以在redis.conf中設定:

aof-load-truncated yes

可記錄時間戳幫助恢復資料

如果在AOF記錄時間戳,可能會與現有的AOF解析器不相容,預設關閉

redis.conf中設定:

aof-timestamp-enabled no

RDB檔案丟失

當RDB檔案丟失時,會導致Redis無法恢復資料。為了解決這個問題,可以使用備份的AOF檔案或者其他節點的RDB檔案來恢復資料,或者增加RDB的快照頻率來減少資料丟失的風險

RDB檔案損壞

當RDB檔案損壞時,會導致Redis無法恢復資料。為了解決這個問題,可以使用redis-check-rdb工具來檢查和修復RDB檔案,或者使用備份的AOF檔案或者其他節點的RDB檔案來恢復資料