1. 程式人生 > >作為一款記憶體資料庫,為什麼斷電後Redis資料不會丟失

作為一款記憶體資料庫,為什麼斷電後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` 中配置檔案預設配置如下,只要達到這三個條件中的任意一個,就會觸發 `Redis` 的`RDB` 持久化機制。 ```java 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` 持久化機制還有如下一些相關命令: - `dir`:`rdb` 檔案生成目錄。預設是 `./`(當前目錄),可以執行命令 `config get dir` 進行檢視,如下圖所示說明當前 `dump` 檔案生成目錄為 `/usr/local/redis-5.0.5/bin`: ![](https://img2020.cnblogs.com/blog/2232223/202101/2232223-20210130100551703-1455016297.png) - `dbfilename`:`rdb` 檔名。預設是 `dump.rdb`。 - `rdbcompression`:`rdb` 檔案是否是 `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` 檔案中的命令來恢復資料。 **`AOF` 和 `RDB` 最大的不同是:`AOF` 記錄的是執行命令(類似於 `MySQL` 中 `binlog` 的 `statement` 格式),而`RDB` 記錄的是資料(類似於 `MySQL` 中 `binlog` 的 `row` 格式)。** 需要注意的是:假如同時開啟了 `RDB` 和 `AOF` 兩種機制,那麼 `Redis` 會優先選擇 `AOF` 持久化檔案來進行資料恢復。 ### AOF 機制如何開啟 `AOF` 機制預設是關閉的,可以通過以下配置檔案進行修改 ```java appendonly no //是否開啟AOF機制,預設是no表示關閉,修改為yes則表示開啟 appendfilename "appendonly.aof" //AOF檔名 ``` PS:和 `RDB` 機制一樣,其生成檔案的路徑也是通過 `dir` 屬性進行配置。 ### AOF 機制資料是否實時寫入磁碟 `AOF` 機制下資料是否實時寫入磁碟,這個和 `MySQL` 的 `redo log` 機制很類似,也是需要通過引數來進行控制。 `AOF` 資料何時寫入磁碟由引數 `appendfsync` 來進行控制: | appendfsync | 描述 | 備註 | | ----------- | ------------------------------------------------------------ | ------------ | | always | 寫入快取的同時通知作業系統重新整理(fsync)到磁碟(但是也可能會有部分作業系統只是儘快刷盤,而不是實時刷盤) | Slow, Safest | | everysec | 先寫入快取,然後每秒中刷一次盤(預設值),這種模式極端情況可能會丟失 1s 的資料 | Compromise | | no | 只寫入快取,什麼時候刷盤由作業系統自己決定 | Faster | ### AOF 檔案重寫 `AOF` 機制主要是通過記錄執行命令的方式來實現的,那麼隨著時間的增加,`AOF` 檔案不可避免的會越來越大,而且可能會出現很多冗餘命令。比如同一個 `key` 值執行了 `10000` 次 `set` 操作,實際上前面 `9999` 次對恢復資料來說都是沒用的,只需要執行最後一次命令就可以把資料恢復,正是為了避免這種問題,`AOF` 機制就提供了檔案重寫功能。 #### 重寫原理分析 `AOF` 重寫時 `Redis` 並不會去分析原有的檔案,因為如果原有檔案過大,分析也會很耗時,所以 **`Redis` 選擇的做法就是重新去 `Redis` 中讀取現有的鍵值對,然後用一條命令記錄鍵值對的值**。 只使用一條命令也有一個前提,那就是一個集合鍵或者列表鍵或者雜湊鍵內包含的元素不能超過 `64` 個,一旦超過 `64` 個,就會使用多條命令來進行記錄。 #### AOF 重寫緩衝區 `AOF` 重寫的時候一般都會有大量的寫操作,所以為了不阻塞客戶端的命令請求,`Redis` 會把重寫操作放入到子程序中執行,但是放入子程序中執行也會帶來一個問題,那就是重寫期間如果同時又執行了客戶端發過來的命令,又該如何保證資料的一致性? 為了解決資料不一致問題,`Redis` 中引入了一個 `AOF` 重寫緩衝區。當開始執行 `AOF` 檔案重寫之後又接收到客戶端的請求命令,不但要將命令寫入原本的 `AOF` 緩衝區(根據上面提到的引數刷盤),還要同時寫 入 `AOF` 重寫緩衝區: ![](https://img2020.cnblogs.com/blog/2232223/202101/2232223-20210130100647874-1224035842.png) 一旦子程序完成了 `AOF` 檔案的重寫,此時會向父程序發出訊號,父程序收到訊號之後會進行阻塞(阻塞期間不執行任何命令),並進行以下兩項工作: 1. 將 `AOF` 重寫緩衝區的檔案重新整理到新的 `AOF` 檔案內。 2. 將新 `AOF` 檔案進行改名並原子的替換掉舊的 `AOF` 檔案。 完成了上面的兩項工作之後,整個 `AOF` 重寫工作完成,父程序開始正常接收命令。 #### AOF 機制觸發條件 `AOF` 機制的觸發條件同樣也分為自動觸發和手動觸發。 - 自動觸發:自動觸發可以通過以下引數進行設定: ```java 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` 檔案是追加形式,可能會遇到 `BRPOP`、`LPUSH` 等阻塞命令的錯誤,從而導致生成的 `AOF` 在重新載入時不能複製完全相同的資料集,而 `RDB` 檔案每次都是重新從頭建立快照,這在一定程度上來說 `RDB` 檔案更加健壯。 # 總結 本文主要介紹了 `Redis` 的兩種持久化機制:`RDB` 和 `AOF`,並分別介紹了兩種持久化機制的原理,通過對兩種持久化機制的對比分析了兩種持久化機制各自的優點和