作為一款記憶體資料庫,為什麼斷電後Redis資料不會丟失

雙子孤狼發表於2021-01-30

前言

Redis 作為一款記憶體資料庫,被廣泛使用於快取,分散式鎖等場景,那麼假如斷電或者因其他因素導致 Reids 服務當機,在重啟之後資料會丟失嗎?

Redis 持久化機制

Redis 雖然是定義為一個記憶體資料庫,但是其也支援資料的持久化,在 Redis 中提供了兩種持久化機制:RDB 持久化和 AOF 持久化。

RDB 持久化機制

RDB 全稱為:Redis DataBase,是 Redis 當中預設的持久化方案。當觸發持久化條件時,Redis 預設會生成一個 dump.rdb 檔案,Redis 在重啟的時候就會通過解析 dump.rdb 檔案進行資料恢復。

RDB 機制觸發條件

RDB 持久化機制有兩種觸發方式:自動觸發和手動觸發。

自動觸發

自動觸發方式也可以分為三種:

  • 執行 flushall 命令(flushdb 命令不會觸發)時,不過此時生成的 dump 檔案內的資料是空的(dump 檔案還會儲存一些頭資訊,所以檔案本身是有內容的,只是沒有資料),沒有什麼太大的實際意義。
  • 執行 shutdown 命令時會觸發生成 dump 檔案。
  • 通過配置檔案自動生成,Redis 中配置檔案預設配置如下,只要達到這三個條件中的任意一個,就會觸發 RedisRDB 持久化機制。
save 900 1 //900秒內至少有1個key被新增或者更新
save 300 10 //300秒內至少有10個key被新增或者更新
save 60 10000 //60秒內至少有10000個key被新增或者更新

手動觸發

除了自動觸發,Redis 中還提供了 2 個手動觸發 RDB 機制的命令(這兩個命令不能同時被執行,一旦一個命令正在執行中,另一個命令會被拒絕執行):

  • save:這個命令會阻塞 Redis 伺服器程式,直到成功建立 RDB 檔案,也就是說在生成 RDB 檔案之前,伺服器不能處理客戶端傳送的任何命令。
  • bgsave:父程式會執行 fork 操作來建立一個子程式。RDB 檔案由子程式來負責生成,父程式可以正常處理客戶端傳送的命令(這裡也是 Redis 不僅僅只是單執行緒的一個體現)。

如果想要知道上一次成功執行 save 或者 bgsave 命令的時間,可以執行 lastsave 命令進行檢視,lastsave 命令返回的是一個 unix 時間戳。

RDB 機制相關配置檔案

除了上面提到的觸發生成 rdb 檔案的配置引數,RDB 持久化機制還有如下一些相關命令:

  • dirrdb 檔案生成目錄。預設是 ./(當前目錄),可以執行命令 config get dir 進行檢視,如下圖所示說明當前 dump 檔案生成目錄為 /usr/local/redis-5.0.5/bin

  • dbfilenamerdb 檔名。預設是 dump.rdb

  • rdbcompressionrdb 檔案是否是 LZF 壓縮檔案。預設是 yes

  • rdbchecksum:是否開啟資料校驗。預設是 yes

RDB 機制優點

  • RDB 是一個非常緊湊的壓縮檔案,儲存了不同時間點上的檔案,非常適合用來災備和資料恢復。
  • RDB 最大限度地提高了 Redis 的效能,因為 Redis 父程式需要做的唯一的工作就是派生一個子程式來完成剩下的工作,父程式永遠不會執行磁碟 I/O 或類似的耗時操作。
  • 與後面介紹的 AOF 持久化機制比較,RDB 方式恢復資料的速度更快。

RDB 機制缺點

  • RDB 無法做到實時備份,所以如果 Redis 因異常停止工作而沒有正確的關機,那麼從上一次備份的到異常當機的這一段時間的資料將會丟失。
  • 2、RDB 通常需要父程式來執行 fork 操作建立子執行緒,所以如果頻繁執行 fork 操作而 CPU 效能又不是很高的話可能會造成短時間內父程式不可用。

AOF 持久化機制

AOF 全稱為:Append Only File,是 Redis 當中提供的另一種持久化機制。AOF 採用日誌的形式將每個寫操作追加到檔案中。開啟 AOF 機制後,只要執行更改 Redis 資料的命令時,命令就會被寫入到 AOF 檔案中。在 Redis 重啟的時候會根據日誌內容依次執行 AOF 檔案中的命令來恢復資料。

AOFRDB 最大的不同是:AOF 記錄的是執行命令(類似於 MySQLbinlogstatement 格式),而RDB 記錄的是資料(類似於 MySQLbinlogrow 格式)。

需要注意的是:假如同時開啟了 RDBAOF 兩種機制,那麼 Redis 會優先選擇 AOF 持久化檔案來進行資料恢復。

AOF 機制如何開啟

AOF 機制預設是關閉的,可以通過以下配置檔案進行修改

appendonly no  //是否開啟AOF機制,預設是no表示關閉,修改為yes則表示開啟
appendfilename "appendonly.aof"  //AOF檔名

PS:和 RDB 機制一樣,其生成檔案的路徑也是通過 dir 屬性進行配置。

AOF 機制資料是否實時寫入磁碟

AOF 機制下資料是否實時寫入磁碟,這個和 MySQLredo log 機制很類似,也是需要通過引數來進行控制。

AOF 資料何時寫入磁碟由引數 appendfsync 來進行控制:

appendfsync 描述 備註
always 寫入快取的同時通知作業系統重新整理(fsync)到磁碟(但是也可能會有部分作業系統只是儘快刷盤,而不是實時刷盤) Slow, Safest
everysec 先寫入快取,然後每秒中刷一次盤(預設值),這種模式極端情況可能會丟失 1s 的資料 Compromise
no 只寫入快取,什麼時候刷盤由作業系統自己決定 Faster

AOF 檔案重寫

AOF 機制主要是通過記錄執行命令的方式來實現的,那麼隨著時間的增加,AOF 檔案不可避免的會越來越大,而且可能會出現很多冗餘命令。比如同一個 key 值執行了 10000set 操作,實際上前面 9999 次對恢復資料來說都是沒用的,只需要執行最後一次命令就可以把資料恢復,正是為了避免這種問題,AOF 機制就提供了檔案重寫功能。

重寫原理分析

AOF 重寫時 Redis 並不會去分析原有的檔案,因為如果原有檔案過大,分析也會很耗時,所以 Redis 選擇的做法就是重新去 Redis 中讀取現有的鍵值對,然後用一條命令記錄鍵值對的值

只使用一條命令也有一個前提,那就是一個集合鍵或者列表鍵或者雜湊鍵內包含的元素不能超過 64 個,一旦超過 64 個,就會使用多條命令來進行記錄。

AOF 重寫緩衝區

AOF 重寫的時候一般都會有大量的寫操作,所以為了不阻塞客戶端的命令請求,Redis 會把重寫操作放入到子程式中執行,但是放入子程式中執行也會帶來一個問題,那就是重寫期間如果同時又執行了客戶端發過來的命令,又該如何保證資料的一致性?

為了解決資料不一致問題,Redis 中引入了一個 AOF 重寫緩衝區。當開始執行 AOF 檔案重寫之後又接收到客戶端的請求命令,不但要將命令寫入原本的 AOF 緩衝區(根據上面提到的引數刷盤),還要同時寫 入 AOF 重寫緩衝區:

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

  1. AOF 重寫緩衝區的檔案重新整理到新的 AOF 檔案內。
  2. 將新 AOF 檔案進行改名並原子的替換掉舊的 AOF 檔案。

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

AOF 機制觸發條件

AOF 機制的觸發條件同樣也分為自動觸發和手動觸發。

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

注意:bgrewriteaof 命令也不能和上面 RDB 持久化命令 bgsave 同時執行,這麼做是為了避免同時建立兩個子程式來同時執行大量寫磁碟操作,影響到 Redis 的效能。

AOF 機制機制優點

  • 使用 AOF 機制,可以自由選擇不同 fsync (刷盤)策略,而且在預設策略下最多也僅僅是損失 1s 的資料。
  • AOF 日誌是一個僅追加的日誌,因此如果出現斷電,也不存在查詢或損壞問題。即使由於某些原因(磁碟已滿或其他原因),日誌已經寫了一半的命令結束,redis-check-aof工具也能夠輕鬆地修復它。
  • AOF 檔案變得太大時,Redis 能夠在後臺自動重寫。
  • 不同於 RDB 的檔案格式,AOF 是一種易於理解和解析的格式,依次包含所有操作的日誌。

AOF 機制機制缺點

  • 對於相同的資料集,AOF 檔案通常比等效的 RDB 檔案大。
  • 根據 fsync 的具體策略,AOF 機制可能比 RDB 機制慢。但是一般情況下,fsync 設定為每秒的效能仍然很高,禁用 fsync 後,即使在高負載下,它的速度也能和 RDB 一樣快。
  • 因為 AOF 檔案是追加形式,可能會遇到 BRPOPLPUSH 等阻塞命令的錯誤,從而導致生成的 AOF 在重新載入時不能複製完全相同的資料集,而 RDB 檔案每次都是重新從頭建立快照,這在一定程度上來說 RDB 檔案更加健壯。

總結

本文主要介紹了 Redis 的兩種持久化機制:RDBAOF,並分別介紹了兩種持久化機制的原理,通過對兩種持久化機制的對比分析了兩種持久化機制各自的優點和缺點。

相關文章