這篇文章將為大家詳細(xì)講解有關(guān)Redis中磁盤持久化機(jī)制的示例分析,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
成都創(chuàng)新互聯(lián)公司不只是一家網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司;我們對(duì)營(yíng)銷、技術(shù)、服務(wù)都有自己獨(dú)特見解,公司采取“創(chuàng)意+綜合+營(yíng)銷”一體化的方式為您提供更專業(yè)的服務(wù)!我們經(jīng)歷的每一步也許不一定是最完美的,但每一步都有值得深思的意義。我們珍視每一份信任,關(guān)注我們的成都網(wǎng)站建設(shè)、成都網(wǎng)站制作質(zhì)量和服務(wù)品質(zhì),在得到用戶滿意的同時(shí),也能得到同行業(yè)的專業(yè)認(rèn)可,能夠?yàn)樾袠I(yè)創(chuàng)新發(fā)展助力。未來(lái)將繼續(xù)專注于技術(shù)創(chuàng)新,服務(wù)升級(jí),滿足企業(yè)一站式成都營(yíng)銷網(wǎng)站建設(shè)需求,讓再小的成都品牌網(wǎng)站建設(shè)也能產(chǎn)生價(jià)值!正文
Redis 是一個(gè)基于 K-V 存儲(chǔ)的數(shù)據(jù)庫(kù)服務(wù)器,下面先介紹 Redis 數(shù)據(jù)庫(kù)的內(nèi)部構(gòu)造以及 K-V 的存儲(chǔ)形式,有助于我們更容易理解 Redis 的持久化機(jī)制。
1. Redis數(shù)據(jù)庫(kù)結(jié)構(gòu)
一個(gè)單機(jī)的 Redis 服務(wù)器默認(rèn)情況下有 16 個(gè)數(shù)據(jù)庫(kù)(0-15號(hào)),默認(rèn)使用的是 0 號(hào)數(shù)據(jù)庫(kù),可以使用 SELECT 命令切換數(shù)據(jù)庫(kù)。
Redis 中的每個(gè)數(shù)據(jù)庫(kù)都由一個(gè) redis.h/redisDb 結(jié)構(gòu)表示,它記錄了單個(gè) Redis 數(shù)據(jù)庫(kù)的鍵空間、所有鍵的過(guò)期時(shí)間、處于阻塞狀態(tài)和就緒狀態(tài)的鍵、數(shù)據(jù)庫(kù)編號(hào)等等。
typedef struct redisDb { // 數(shù)據(jù)庫(kù)鍵空間,保存著數(shù)據(jù)庫(kù)中的所有鍵值對(duì) dict *dict; // 鍵的過(guò)期時(shí)間,字典的鍵為鍵,字典的值為過(guò)期事件 UNIX 時(shí)間戳 dict *expires; // 正處于阻塞狀態(tài)的鍵 dict *blocking_keys; // 可以解除阻塞的鍵 dict *ready_keys; // 正在被 WATCH 命令監(jiān)視的鍵 dict *watched_keys; struct evictionPoolEntry *eviction_pool; // 數(shù)據(jù)庫(kù)編號(hào) int id; // 數(shù)據(jù)庫(kù)的鍵的平均 TTL,統(tǒng)計(jì)信息 long long avg_ttl; } redisDb;
由于 Redis 是一個(gè)鍵值對(duì)數(shù)據(jù)庫(kù)(key-value pairs database), 所以它的數(shù)據(jù)庫(kù)本身也是一個(gè)字典,對(duì)應(yīng)的結(jié)構(gòu)正是 redisDb。其中,dict 指向的是一個(gè)記錄鍵值對(duì)數(shù)據(jù)的字典,它的鍵是一個(gè)字符串對(duì)象,它的值則可以是字符串、列表、哈希表、集合和有序集合在內(nèi)的任意一種 Redis 類型對(duì)象。 expires 指向的是一個(gè)用于記錄鍵的過(guò)期時(shí)間的字典,它的鍵為 dict 中的數(shù)據(jù)庫(kù)鍵,它的值為這個(gè)數(shù)據(jù)庫(kù)鍵的過(guò)期時(shí)間戳,這個(gè)值以 long long 類型表示。
2. RDB持久化
RDB 持久化(也稱作快照持久化)是指將內(nèi)存中的數(shù)據(jù)生成快照保存到磁盤里面,保存的文件后綴是 .rdb。rdb 文件是一個(gè)經(jīng)過(guò)壓縮的二進(jìn)制文件,當(dāng) Redis 重新啟動(dòng)時(shí),可以讀取 rdb 快照文件恢復(fù)數(shù)據(jù)。RDB 功能最核心的是 rdbSave 和 rdbLoad 兩個(gè)函數(shù), 前者用于生成 RDB 文件并保存到磁盤,而后者則用于將 RDB 文件中的數(shù)據(jù)重新載入到內(nèi)存中:
RDB 文件是一個(gè)單文件的全量數(shù)據(jù),很適合數(shù)據(jù)的容災(zāi)備份與恢復(fù),通過(guò) RDB 文件恢復(fù)數(shù)據(jù)庫(kù)耗時(shí)較短,通常 1G 的快照文件載入內(nèi)存只需 20s 左右。Redis 提供了手動(dòng)觸發(fā)保存、自動(dòng)保存間隔兩種 RDB 文件的生成方式,下面先介紹 RDB 的創(chuàng)建和載入過(guò)程。
2.1. RDB的創(chuàng)建和載入
2.1.1. 手動(dòng)觸發(fā)保存
Redis 提供了兩個(gè)用于生成 RDB 文件的命令,一個(gè)是 SAVE,另一個(gè)是 BGSAVE。而觸發(fā) Redis 進(jìn)行 RDB 備份的方式有兩種,一種是通過(guò) SAVE 命令、BGSAVE 命令手動(dòng)觸發(fā)快照生成的方式,另一種是配置保存時(shí)間和寫入次數(shù),由 Redis 根據(jù)條件自動(dòng)觸發(fā)保存操作。
1. SAVE命令
SAVE 是一個(gè)同步式的命令,它會(huì)阻塞 Redis 服務(wù)器進(jìn)程,直到 RDB 文件創(chuàng)建完成為止。在服務(wù)器進(jìn)程阻塞期間,服務(wù)器不能處理任何其他命令請(qǐng)求。
客戶端命令
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ù)端進(jìn)程(PID為6266)執(zhí)行了 SAVE 操作,這個(gè)操作發(fā)生期間會(huì)一直阻塞 Redis 客戶端的請(qǐng)求處理。
2. BGSAVE命令
BGSAVE 是一個(gè)異步式的命令,和 SAVE 命令直接阻塞服務(wù)器進(jìn)程的做法不同,BGSAVE 命令會(huì)派生出一個(gè)子進(jìn)程,由子進(jìn)程負(fù)責(zé)創(chuàng)建 RDB 文件,服務(wù)器進(jìn)程(父進(jìn)程)繼續(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
通過(guò)服務(wù)端輸出的日志,可以發(fā)現(xiàn)Redis 在服務(wù)端進(jìn)程(PID為6266)會(huì)為 BGSAVE 命令單獨(dú)創(chuàng)建(fork)一個(gè)子進(jìn)程(PID為6283),并由子進(jìn)程在后臺(tái)完成 RDB 的保存過(guò)程,在操作完成之后通知父進(jìn)程然后退出。在整個(gè)過(guò)程中,服務(wù)器進(jìn)程只會(huì)消耗少量時(shí)間在創(chuàng)建子進(jìn)程和處理子進(jìn)程信號(hào)量上面,其余時(shí)間都是待命狀態(tài)。
BGSAVE 是觸發(fā) RDB 持久化的主流方式,下面給出 BGSAVE 命令生成快照的流程:
客戶端發(fā)起 BGSAVE 命令,Redis 主進(jìn)程判斷當(dāng)前是否存在正在執(zhí)行備份的子進(jìn)程,如果存在則直接返回
父進(jìn)程 fork 一個(gè)子進(jìn)程 (fork 的過(guò)程中會(huì)造成阻塞的情況),這個(gè)過(guò)程可以使用 info stats 命令查看 latest_fork_usec 選項(xiàng),查看最近一次 fork 操作消耗的時(shí)間,單位是微秒
父進(jìn)程 fork 完成之后,則會(huì)返回 Background saving started 的信息提示,此時(shí) fork 阻塞解除
fork 創(chuàng)建的子進(jìn)程開始根據(jù)父進(jìn)程的內(nèi)存數(shù)據(jù)生成臨時(shí)的快照文件,然后替換原文件
子進(jìn)程備份完畢后向父進(jìn)程發(fā)送完成信息,父進(jìn)程更新統(tǒng)計(jì)信息
3. SAVE和BGSAVE的比較
命令 | SAVE | BGSAVE |
---|---|---|
IO類型 | 同步 | 異步 |
是否阻塞 | 全程阻塞 | fork時(shí)發(fā)生阻塞 |
復(fù)雜度 | O(n) | O(n) |
優(yōu)點(diǎn) | 不會(huì)消耗額外的內(nèi)存 | 不阻塞客戶端 |
缺點(diǎn) | 阻塞客戶端 | fork子進(jìn)程消耗內(nèi)存 |
2.1.2. 自動(dòng)觸發(fā)保存
因?yàn)?BGSAVE 命令可以在不阻塞服務(wù)器進(jìn)程的情況下執(zhí)行,所以 Redis 的配置文件 redis.conf 提供了一個(gè) save 選項(xiàng),讓服務(wù)器每隔一段時(shí)間自動(dòng)執(zhí)行一次 BGSAVE 命令。用戶可以通過(guò) save 選項(xiàng)設(shè)置多個(gè)保存條件,只要其中任意一個(gè)條件被滿足,服務(wù)器就會(huì)執(zhí)行 BGSAVE 命令。 Redis 配置文件 redis.conf 默認(rèn)配置了以下 3 個(gè)保存條件:
save 900 1 save 300 10 save 60 10000
那么只要滿足以下 3 個(gè)條件中的任意一個(gè),BGSAVE 命令就會(huì)被自動(dòng)執(zhí)行:
服務(wù)器在 900 秒之內(nèi),對(duì)數(shù)據(jù)庫(kù)進(jìn)行了至少 1 次修改。
服務(wù)器在 300 秒之內(nèi),對(duì)數(shù)據(jù)庫(kù)進(jìn)行了至少 10 次修改。
服務(wù)器在 60 秒之內(nèi),對(duì)數(shù)據(jù)庫(kù)進(jìn)行了至少 10000 次修改。
Redis 服務(wù)器會(huì)周期性地操作 serverCron 函數(shù),這個(gè)函數(shù)每隔 100 毫秒就會(huì)執(zhí)行一次,它的一項(xiàng)任務(wù)就是檢查 save 選項(xiàng)所設(shè)置的保存條件是否滿足,如果滿足的話,就自動(dòng)執(zhí)行 BGSAVE 命令。
2.1.3. 啟動(dòng)自動(dòng)載入
和使用 SAVE 和 BGSAVE 命令創(chuàng)建 RDB 文件不同,Redis 沒有專門提供用于載入 RDB 文件的命令,RDB 文件的載入過(guò)程是在 Redis 服務(wù)器啟動(dòng)時(shí)自動(dòng)完成的。啟動(dòng)時(shí)只要在指定目錄檢測(cè)到 RDB 文件的存在,Redis 就會(huì)通過(guò) rdbLoad 函數(shù)自動(dòng)載入 RDB 文件。
下面是 Redis 服務(wù)器啟動(dòng)時(shí)打印的日志,倒數(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ù)器會(huì)優(yōu)先使用 AOF 文件來(lái)還原數(shù)據(jù)庫(kù)狀態(tài);只有在 AOF 的持久化功能處于關(guān)閉狀態(tài)時(shí),服務(wù)器才會(huì)使用優(yōu)先使用 RDB 文件還原數(shù)據(jù)庫(kù)狀態(tài)。
2.2. RDB的文件結(jié)構(gòu)
RDB 文件是經(jīng)過(guò)壓縮的二進(jìn)制文件,下面介紹關(guān)于RDB文件的一些細(xì)節(jié)。
2.2.1. 存儲(chǔ)路徑
SAVE 命令和 BGSAVE 命令都只會(huì)備份當(dāng)前數(shù)據(jù)庫(kù),備份文件名默認(rèn)為 dump.rdb,可通過(guò)配置文件修改備份文件名 dbfilename xxx.rdb??梢酝ㄟ^(guò)以下命令查看備份文件目錄和 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 文件的存儲(chǔ)路徑既可以在啟動(dòng)前配置,也可以通過(guò)命令動(dòng)態(tài)設(shè)定。
配置項(xiàng):通過(guò) dir 配置指定目錄,dbfilename 指定文件名
動(dòng)態(tài)指定:Redis 啟動(dòng)后也可以動(dòng)態(tài)修改 RDB 存儲(chǔ)路徑,在磁盤損害或空間不足時(shí)非常有用,執(zhí)行命令為:
config set dir {newdir} config set dbfilename {newFileName}
關(guān)于“Redis中磁盤持久化機(jī)制的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。