溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Redis中磁盤持久化機制的示例分析

發(fā)布時間:2021-08-21 14:16:25 來源:億速云 閱讀:116 作者:小新 欄目:數(shù)據(jù)庫

這篇文章將為大家詳細講解有關(guān)Redis中磁盤持久化機制的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

正文

Redis 是一個基于 K-V 存儲的數(shù)據(jù)庫服務(wù)器,下面先介紹 Redis 數(shù)據(jù)庫的內(nèi)部構(gòu)造以及 K-V 的存儲形式,有助于我們更容易理解 Redis 的持久化機制。

1. Redis數(shù)據(jù)庫結(jié)構(gòu)

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

Redis中磁盤持久化機制的示例分析

Redis 中的每個數(shù)據(jù)庫都由一個 redis.h/redisDb 結(jié)構(gòu)表示,它記錄了單個 Redis 數(shù)據(jù)庫的鍵空間、所有鍵的過期時間、處于阻塞狀態(tài)和就緒狀態(tài)的鍵、數(shù)據(jù)庫編號等等。

typedef struct redisDb {
 // 數(shù)據(jù)庫鍵空間,保存著數(shù)據(jù)庫中的所有鍵值對
 dict *dict;
 // 鍵的過期時間,字典的鍵為鍵,字典的值為過期事件 UNIX 時間戳
 dict *expires;
 // 正處于阻塞狀態(tài)的鍵
 dict *blocking_keys;
 // 可以解除阻塞的鍵
 dict *ready_keys;
 // 正在被 WATCH 命令監(jiān)視的鍵
 dict *watched_keys;
 struct evictionPoolEntry *eviction_pool;
 // 數(shù)據(jù)庫編號
 int id;
 // 數(shù)據(jù)庫的鍵的平均 TTL,統(tǒng)計信息
 long long avg_ttl;
} redisDb;

由于 Redis 是一個鍵值對數(shù)據(jù)庫(key-value pairs database), 所以它的數(shù)據(jù)庫本身也是一個字典,對應(yīng)的結(jié)構(gòu)正是 redisDb。其中,dict 指向的是一個記錄鍵值對數(shù)據(jù)的字典,它的鍵是一個字符串對象,它的值則可以是字符串、列表、哈希表、集合和有序集合在內(nèi)的任意一種 Redis 類型對象。 expires 指向的是一個用于記錄鍵的過期時間的字典,它的鍵為 dict 中的數(shù)據(jù)庫鍵,它的值為這個數(shù)據(jù)庫鍵的過期時間戳,這個值以 long long 類型表示。

Redis中磁盤持久化機制的示例分析

2. RDB持久化

RDB 持久化(也稱作快照持久化)是指將內(nèi)存中的數(shù)據(jù)生成快照保存到磁盤里面,保存的文件后綴是 .rdb。rdb 文件是一個經(jīng)過壓縮的二進制文件,當 Redis 重新啟動時,可以讀取 rdb 快照文件恢復(fù)數(shù)據(jù)。RDB 功能最核心的是 rdbSave 和 rdbLoad 兩個函數(shù), 前者用于生成 RDB 文件并保存到磁盤,而后者則用于將 RDB 文件中的數(shù)據(jù)重新載入到內(nèi)存中:

Redis中磁盤持久化機制的示例分析

RDB 文件是一個單文件的全量數(shù)據(jù),很適合數(shù)據(jù)的容災(zāi)備份與恢復(fù),通過 RDB 文件恢復(fù)數(shù)據(jù)庫耗時較短,通常 1G 的快照文件載入內(nèi)存只需 20s 左右。Redis 提供了手動觸發(fā)保存、自動保存間隔兩種 RDB 文件的生成方式,下面先介紹 RDB 的創(chuàng)建和載入過程。

2.1. RDB的創(chuàng)建和載入

2.1.1. 手動觸發(fā)保存

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

1. SAVE命令

SAVE 是一個同步式的命令,它會阻塞 Redis 服務(wù)器進程,直到 RDB 文件創(chuàng)建完成為止。在服務(wù)器進程阻塞期間,服務(wù)器不能處理任何其他命令請求。

客戶端命令

127.0.0.1:6379> SAVE
OK

服務(wù)端日志

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

執(zhí)行 SAVE 命令后,Redis 在服務(wù)端進程(PID為6266)執(zhí)行了 SAVE 操作,這個操作發(fā)生期間會一直阻塞 Redis 客戶端的請求處理。

2. BGSAVE命令

BGSAVE 是一個異步式的命令,和 SAVE 命令直接阻塞服務(wù)器進程的做法不同,BGSAVE 命令會派生出一個子進程,由子進程負責創(chuàng)建 RDB 文件,服務(wù)器進程(父進程)繼續(xù)處理客戶的命令。

客戶端命令

127.0.0.1:6379> BGSAVE
Background saving started

服務(wù)端日志

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

通過服務(wù)端輸出的日志,可以發(fā)現(xiàn)Redis 在服務(wù)端進程(PID為6266)會為 BGSAVE 命令單獨創(chuàng)建(fork)一個子進程(PID為6283),并由子進程在后臺完成 RDB 的保存過程,在操作完成之后通知父進程然后退出。在整個過程中,服務(wù)器進程只會消耗少量時間在創(chuàng)建子進程和處理子進程信號量上面,其余時間都是待命狀態(tài)。

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

Redis中磁盤持久化機制的示例分析

  1. 客戶端發(fā)起 BGSAVE 命令,Redis 主進程判斷當前是否存在正在執(zhí)行備份的子進程,如果存在則直接返回

  2. 父進程 fork 一個子進程 (fork 的過程中會造成阻塞的情況),這個過程可以使用 info stats 命令查看 latest_fork_usec 選項,查看最近一次 fork 操作消耗的時間,單位是微秒

  3. 父進程 fork 完成之后,則會返回 Background saving started 的信息提示,此時 fork 阻塞解除

  4. fork 創(chuàng)建的子進程開始根據(jù)父進程的內(nèi)存數(shù)據(jù)生成臨時的快照文件,然后替換原文件

  5. 子進程備份完畢后向父進程發(fā)送完成信息,父進程更新統(tǒng)計信息

3. SAVE和BGSAVE的比較

命令SAVEBGSAVE
IO類型同步異步
是否阻塞全程阻塞fork時發(fā)生阻塞
復(fù)雜度O(n)O(n)
優(yōu)點不會消耗額外的內(nèi)存不阻塞客戶端
缺點阻塞客戶端fork子進程消耗內(nèi)存

2.1.2. 自動觸發(fā)保存

因為 BGSAVE 命令可以在不阻塞服務(wù)器進程的情況下執(zhí)行,所以 Redis 的配置文件 redis.conf 提供了一個 save 選項,讓服務(wù)器每隔一段時間自動執(zhí)行一次 BGSAVE 命令。用戶可以通過 save 選項設(shè)置多個保存條件,只要其中任意一個條件被滿足,服務(wù)器就會執(zhí)行 BGSAVE 命令。 Redis 配置文件 redis.conf 默認配置了以下 3 個保存條件:

save 900 1
save 300 10 
save 60 10000

那么只要滿足以下 3 個條件中的任意一個,BGSAVE 命令就會被自動執(zhí)行:

  • 服務(wù)器在 900 秒之內(nèi),對數(shù)據(jù)庫進行了至少 1 次修改。

  • 服務(wù)器在 300 秒之內(nèi),對數(shù)據(jù)庫進行了至少 10 次修改。

  • 服務(wù)器在 60 秒之內(nèi),對數(shù)據(jù)庫進行了至少 10000 次修改。

Redis 服務(wù)器會周期性地操作 serverCron 函數(shù),這個函數(shù)每隔 100 毫秒就會執(zhí)行一次,它的一項任務(wù)就是檢查 save 選項所設(shè)置的保存條件是否滿足,如果滿足的話,就自動執(zhí)行 BGSAVE 命令。

2.1.3. 啟動自動載入

和使用 SAVE 和 BGSAVE 命令創(chuàng)建 RDB 文件不同,Redis 沒有專門提供用于載入 RDB 文件的命令,RDB 文件的載入過程是在 Redis 服務(wù)器啟動時自動完成的。啟動時只要在指定目錄檢測到 RDB 文件的存在,Redis 就會通過 rdbLoad 函數(shù)自動載入 RDB 文件。

下面是 Redis 服務(wù)器啟動時打印的日志,倒數(shù)第 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 文件屬于全量的數(shù)據(jù)備份,所以更新頻率比 RDB 文件的更新頻率高。所以如果 Redis 服務(wù)器開啟了 AOF 持久化功能,那么服務(wù)器會優(yōu)先使用 AOF 文件來還原數(shù)據(jù)庫狀態(tài);只有在 AOF 的持久化功能處于關(guān)閉狀態(tài)時,服務(wù)器才會使用優(yōu)先使用 RDB 文件還原數(shù)據(jù)庫狀態(tài)。

Redis中磁盤持久化機制的示例分析

2.2. RDB的文件結(jié)構(gòu)

RDB 文件是經(jīng)過壓縮的二進制文件,下面介紹關(guān)于RDB文件的一些細節(jié)。

2.2.1. 存儲路徑

SAVE 命令和 BGSAVE 命令都只會備份當前數(shù)據(jù)庫,備份文件名默認為 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 文件的存儲路徑既可以在啟動前配置,也可以通過命令動態(tài)設(shè)定。

  • 配置項:通過 dir 配置指定目錄,dbfilename 指定文件名

  • 動態(tài)指定:Redis 啟動后也可以動態(tài)修改 RDB 存儲路徑,在磁盤損害或空間不足時非常有用,執(zhí)行命令為:

config set dir {newdir}
config set dbfilename {newFileName}

關(guān)于“Redis中磁盤持久化機制的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI