作為一款內存數據庫,為什麼斷電後Redis數據不會丟失

前言

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,並分別介紹了兩種持久化機制的原理,通過對兩種持久化機制的對比分析了兩種持久化機制各自的優點和缺點。

Tags: