Redis的磁盤持久化機制

Redis 是內存數據庫,數據都是存儲在內存中,爲了不進程退出致使數據的永久丟失,須要按期將 Redis 中的數據以數據或命令的形式從內存保存到本地磁盤。當下次 Redis 重啓時,利用持久化文件進行數據恢復。Redis 提供了 RDB 和 AOF 兩種持久化機制,前者將當前的數據保存到磁盤,後者則是將每次執行的寫命令保存到磁盤(相似於 MySQL 的 Binlog)。本文將詳細介紹 RDB 和 AOF 兩種持久化方案,包括操做方法和持久化的實現原理。html

正文redis

Redis 是一個基於 K-V 存儲的數據庫服務器,下面先介紹 Redis 數據庫的內部構造以及 K-V 的存儲形式,有助於咱們更容易理解 Redis 的持久化機制。數據庫

1. Redis數據庫結構緩存

一個單機的 Redis 服務器默認狀況下有 16 個數據庫(0-15號),默認使用的是 0 號數據庫,可使用 SELECT 命令切換數據庫。服務器

 

Redis 中的每一個數據庫都由一個 redis.h/redisDb 結構表示,它記錄了單個 Redis 數據庫的鍵空間、全部鍵的過時時間、處於阻塞狀態和就緒狀態的鍵、數據庫編號等等。異步

typedef struct redisDb {
// 數據庫鍵空間,保存着數據庫中的全部鍵值對
dict *dict;
// 鍵的過時時間,字典的鍵爲鍵,字典的值爲過時事件 UNIX 時間戳
dict *expires;
// 正處於阻塞狀態的鍵
dict *blocking_keys;
// 能夠解除阻塞的鍵
dict *ready_keys;
// 正在被 WATCH 命令監視的鍵
dict *watched_keys;
struct evictionPoolEntry *eviction_pool;
// 數據庫編號
int id;
// 數據庫的鍵的平均 TTL,統計信息
long long avg_ttl;
} redisDb;

因爲 Redis 是一個鍵值對數據庫(key-value pairs database), 因此它的數據庫自己也是一個字典,對應的結構正是 redisDb。其中,dict 指向的是一個記錄鍵值對數據的字典,它的鍵是一個字符串對象,它的值則能夠是字符串、列表、哈希表、集合和有序集合在內的任意一種 Redis 類型對象。 expires 指向的是一個用於記錄鍵的過時時間的字典,它的鍵爲 dict 中的數據庫鍵,它的值爲這個數據庫鍵的過時時間戳,這個值以 long long 類型表示。函數

 

2. RDB持久化3d

RDB 持久化(也稱做快照持久化)是指將內存中的數據生成快照保存到磁盤裏面,保存的文件後綴是 .rdb。rdb 文件是一個通過壓縮的二進制文件,當 Redis 從新啓動時,能夠讀取 rdb 快照文件恢復數據。RDB 功能最核心的是 rdbSave 和 rdbLoad 兩個函數, 前者用於生成 RDB 文件並保存到磁盤,然後者則用於將 RDB 文件中的數據從新載入到內存中:日誌

 

RDB 文件是一個單文件的全量數據,很適合數據的容災備份與恢復,經過 RDB 文件恢復數據庫耗時較短,一般 1G 的快照文件載入內存只需 20s 左右。Redis 提供了手動觸發保存、自動保存間隔兩種 RDB 文件的生成方式,下面先介紹 RDB 的建立和載入過程。server

2.1. RDB的建立和載入

2.1.1. 手動觸發保存

Redis 提供了兩個用於生成 RDB 文件的命令,一個是 SAVE,另外一個是 BGSAVE。而觸發 Redis 進行 RDB 備份的方式有兩種,一種是經過 SAVE 命令、BGSAVE 命令手動觸發快照生成的方式,另外一種是配置保存時間和寫入次數,由 Redis 根據條件自動觸發保存操做。

1. SAVE命令

SAVE 是一個同步式的命令,它會阻塞 Redis 服務器進程,直到 RDB 文件建立完成爲止。在服務器進程阻塞期間,服務器不能處理任何其餘命令請求。

客戶端命令

127.0.0.1:6379> SAVE
OK

服務端日誌

6266:M 15 Sep 2019 08:31:01.258 * DB saved on disk

執行 SAVE 命令後,Redis 在服務端進程(PID爲6266)執行了 SAVE 操做,這個操做發生期間會一直阻塞 Redis 客戶端的請求處理。

2. BGSAVE命令

BGSAVE 是一個異步式的命令,和 SAVE 命令直接阻塞服務器進程的作法不一樣,BGSAVE 命令會派生出一個子進程,由子進程負責建立 RDB 文件,服務器進程(父進程)繼續處理客戶的命令。

客戶端命令

127.0.0.1:6379> BGSAVE
Background saving started

服務端日誌

6266:M 15 Sep 2019 08:31:22.914 * Background saving started by pid 6283
6283:C 15 Sep 2019 08:31:22.915 * DB saved on disk
6266:M 15 Sep 2019 08:31:22.934 * Background saving terminated with success

經過服務端輸出的日誌,能夠發現Redis 在服務端進程(PID爲6266)會爲 BGSAVE 命令單首創建(fork)一個子進程(PID爲6283),並由子進程在後臺完成 RDB 的保存過程,在操做完成以後通知父進程而後退出。在整個過程當中,服務器進程只會消耗少許時間在建立子進程和處理子進程信號量上面,其他時間都是待命狀態。

BGSAVE 是觸發 RDB 持久化的主流方式,下面給出 BGSAVE 命令生成快照的流程:

 

  1. 客戶端發起 BGSAVE 命令,Redis 主進程判斷當前是否存在正在執行備份的子進程,若是存在則直接返回
  2. 父進程 fork 一個子進程 (fork 的過程當中會形成阻塞的狀況),這個過程可使用 info stats 命令查看 latest_fork_usec 選項,查看最近一次 fork 操做消耗的時間,單位是微秒
  3. 父進程 fork 完成以後,則會返回 Background saving started 的信息提示,此時 fork 阻塞解除
  4. fork 建立的子進程開始根據父進程的內存數據生成臨時的快照文件,而後替換原文件
  5. 子進程備份完畢後向父進程發送完成信息,父進程更新統計信息

3. SAVE和BGSAVE的比較

 

命令 SAVE BGSAVE
IO類型 同步 異步
是否阻塞 全程阻塞 fork時發生阻塞
複雜度 O(n) O(n)
優勢 不會消耗額外的內存 不阻塞客戶端
缺點 阻塞客戶端 fork子進程消耗內存

 

2.1.2. 自動觸發保存

由於 BGSAVE 命令能夠在不阻塞服務器進程的狀況下執行,因此 Redis 的配置文件 redis.conf 提供了一個 save 選項,讓服務器每隔一段時間自動執行一次 BGSAVE 命令。用戶能夠經過 save 選項設置多個保存條件,只要其中任意一個條件被知足,服務器就會執行 BGSAVE 命令。 Redis 配置文件 redis.conf 默認配置瞭如下 3 個保存條件:

save 900 1
save 300 10
save 60 10000

那麼只要知足如下 3 個條件中的任意一個,BGSAVE 命令就會被自動執行:

  • 服務器在 900 秒以內,對數據庫進行了至少 1 次修改。
  • 服務器在 300 秒以內,對數據庫進行了至少 10 次修改。
  • 服務器在 60 秒以內,對數據庫進行了至少 10000 次修改。

Redis 服務器會週期性地操做 serverCron 函數,這個函數每隔 100 毫秒就會執行一次,它的一項任務就是檢查 save 選項所設置的保存條件是否知足,若是知足的話,就自動執行 BGSAVE 命令。

2.1.3. 啓動自動載入

和使用 SAVE 和 BGSAVE 命令建立 RDB 文件不一樣,Redis 沒有專門提供用於載入 RDB 文件的命令,RDB 文件的載入過程是在 Redis 服務器啓動時自動完成的。啓動時只要在指定目錄檢測到 RDB 文件的存在,Redis 就會經過 rdbLoad 函數自動載入 RDB 文件。

下面是 Redis 服務器啓動時打印的日誌,倒數第 2 條日誌是在成功載入 RDB 文件後打印的。

$ redis-server /usr/local/etc/redis.conf
6266:C 15 Sep 2019 08:30:41.830 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=6266, just started
6266:C 15 Sep 2019 08:30:41.830 # Configuration loaded
6266:M 15 Sep 2019 08:30:41.831 * Increased maximum number of open files to 10032 (it was originally set to 256).
6266:M 15 Sep 2019 08:30:41.832 # Server initialized
6266:M 15 Sep 2019 08:30:41.833 * DB loaded from disk: 0.001 seconds
6266:M 15 Sep 2019 08:30:41.833 * Ready to accept connections

因爲 AOF 文件屬於增量的寫入命令備份,RDB 文件屬於全量的數據備份,因此更新頻率比 RDB 文件的更新頻率高。因此若是 Redis 服務器開啓了 AOF 持久化功能,那麼服務器會優先使用 AOF 文件來還原數據庫狀態;只有在 AOF 的持久化功能處於關閉狀態時,服務器纔會使用優先使用 RDB 文件還原數據庫狀態。

 

2.2. RDB的文件結構

RDB 文件是通過壓縮的二進制文件,下面介紹關於RDB文件的一些細節。

2.2.1. 存儲路徑

SAVE 命令和 BGSAVE 命令都只會備份當前數據庫,備份文件名默認爲 dump.rdb,可經過配置文件修改備份文件名 dbfilename xxx.rdb。能夠經過如下命令查看備份文件目錄和 RDB 文件名稱:

$ redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/usr/local/var/db/redis"
127.0.0.1:6379> CONFIG GET dbfilename
1) "dbfilename"
2) "dump.rdb"

RDB 文件的存儲路徑既能夠在啓動前配置,也能夠經過命令動態設定。

  • 配置項:經過 dir 配置指定目錄,dbfilename 指定文件名
  • 動態指定:Redis 啓動後也能夠動態修改 RDB 存儲路徑,在磁盤損害或空間不足時很是有用,執行命令爲:
config set dir {newdir}
config set dbfilename {newFileName}

文章同步發佈: https://www.geek-share.com/detail/2784034837.html

參考文章:

你對Redis持久化了解多少?一篇文章讓你明白Redis持久化

一篇文章帶你深刻解析Redis主從複製機制!

【Redis緩存機制】快照持久化和AOF持久化

相關文章
相關標籤/搜索