目錄
- 一、概述
- 二、快照怎么用?
- 三、執(zhí)行 bgsava 快照時(shí),數(shù)據(jù)能被修改嗎?
- 四、RDB 和 AOF 合體
一、概述
所謂的快照,就是記錄某一個(gè)瞬間東西,比如當(dāng)我們給風(fēng)景拍照時(shí),那一個(gè)瞬間的畫(huà)面和信息就記錄到了一張照片。
所以,RDB 快照就是記錄某一個(gè)瞬間的內(nèi)存數(shù)據(jù),記錄的是實(shí)際數(shù)據(jù),而 AOF 文件記錄的是命令操作的日志,而不是實(shí)際的數(shù)據(jù)。
因此在 Redis 恢復(fù)數(shù)據(jù)時(shí), RDB 恢復(fù)數(shù)據(jù)的效率會(huì)比 AOF 快些,因?yàn)橹苯訉?RDB 文件讀入內(nèi)存就可以了,不需要像 AOF 那樣還需要額外執(zhí)行操作命令的步驟才能恢復(fù)數(shù)據(jù)。
接下來(lái),就來(lái)具體聊聊 RDB 快照 。
二、快照怎么用?
要熟悉一個(gè)東西,先看看怎么用是比較好的方式。
Redis 提供了兩個(gè)命令來(lái)生成 RDB 文件,分別是 save
和 bgsave
,他們的區(qū)別就在于是否在「主線程」里執(zhí)行:
- 執(zhí)行了 save 命令,就會(huì)在主線程生成 RDB 文件,由于和執(zhí)行操作命令在同一個(gè)線程,所以如果寫(xiě)入 RDB 文件的時(shí)間太長(zhǎng),會(huì)阻塞主線程;
- 執(zhí)行了 bgsava 命令,會(huì)創(chuàng)建一個(gè)子進(jìn)程來(lái)生成 RDB 文件,這樣可以避免主線程的阻塞;
RDB 文件的加載工作是在服務(wù)器啟動(dòng)時(shí)自動(dòng)執(zhí)行的,Redis 并沒(méi)有提供專門(mén)用于加載 RDB 文件的命令。
Redis 還可以通過(guò)配置文件的選項(xiàng)來(lái)實(shí)現(xiàn)每隔一段時(shí)間自動(dòng)執(zhí)行一次 bgsava 命令,默認(rèn)會(huì)提供以下配置:
save 900 1
save 300 10
save 60 10000
別看選項(xiàng)名叫 sava,實(shí)際上執(zhí)行的是 bgsava 命令,也就是會(huì)創(chuàng)建子進(jìn)程來(lái)生成 RDB 快照文件。
只要滿足上面條件的任意一個(gè),就會(huì)執(zhí)行 bgsava,它們的意思分別是:
- 900 秒之內(nèi),對(duì)數(shù)據(jù)庫(kù)進(jìn)行了至少 1 次修改;
- 300 秒之內(nèi),對(duì)數(shù)據(jù)庫(kù)進(jìn)行了至少 10 次修改;
- 60 秒之內(nèi),對(duì)數(shù)據(jù)庫(kù)進(jìn)行了至少 10000 次修改。
這里提一點(diǎn),Redis 的快照是全量快照,也就是說(shuō)每次執(zhí)行快照,都是把內(nèi)存中的「所有數(shù)據(jù)」都記錄到磁盤(pán)中。
所以可以認(rèn)為,執(zhí)行快照是一個(gè)比較重的操作,如果頻率太頻繁,可能會(huì)對(duì) Redis 性能產(chǎn)生影響。如果頻率太低,服務(wù)器故障時(shí),丟失的數(shù)據(jù)會(huì)更多。
通常可能設(shè)置至少 5 分鐘才保存一次快照,這時(shí)如果 Redis 出現(xiàn)宕機(jī)等情況,則意味著最多可能丟失 5 分鐘數(shù)據(jù)。
這就是 RDB 快照的缺點(diǎn),在服務(wù)器發(fā)生故障時(shí),丟失的數(shù)據(jù)會(huì)比 AOF 持久化的方式更多,因?yàn)?RDB 快照是全量快照的方式,因此執(zhí)行的頻率不能太頻繁,否則會(huì)影響 Redis 性能,而 AOF 日志可以以秒級(jí)的方式記錄操作命令,所以丟失的數(shù)據(jù)就相對(duì)更少。
三、執(zhí)行 bgsava 快照時(shí),數(shù)據(jù)能被修改嗎?
那問(wèn)題來(lái)了,執(zhí)行 bgsava 過(guò)程中,由于是交給子進(jìn)程來(lái)構(gòu)建 RDB 文件,主線程還是可以繼續(xù)工作的,此時(shí)主線程可以修改數(shù)據(jù)嗎?
如果不可以修改數(shù)據(jù)的話,那這樣性能一下就降低了很多。如果可以修改數(shù)據(jù),又是如何做到到呢?
直接說(shuō)結(jié)論吧,執(zhí)行 bgsava 過(guò)程中,Redis 依然可以繼續(xù)處理操作命令的,也就是數(shù)據(jù)是能被修改的。
那具體如何做到到呢?關(guān)鍵的技術(shù)就在于寫(xiě)時(shí)復(fù)制技術(shù)(Copy-On-Write, COW)。
執(zhí)行 bgsava 命令的時(shí)候,會(huì)通過(guò) fork()
創(chuàng)建子進(jìn)程,此時(shí)子進(jìn)程和父進(jìn)程是共享同一片內(nèi)存數(shù)據(jù)的,因?yàn)閯?chuàng)建子進(jìn)程的時(shí)候,會(huì)復(fù)制父進(jìn)程的頁(yè)表,但是頁(yè)表指向的物理內(nèi)存還是一個(gè)。

只有在發(fā)生修改內(nèi)存數(shù)據(jù)的情況時(shí),物理內(nèi)存才會(huì)被復(fù)制一份。

這樣的目的是為了減少創(chuàng)建子進(jìn)程時(shí)的性能損耗,從而加快創(chuàng)建子進(jìn)程的速度,畢竟創(chuàng)建子進(jìn)程的過(guò)程中,是會(huì)阻塞主線程的。
所以,創(chuàng)建 bgsave 子進(jìn)程后,由于共享父進(jìn)程的所有內(nèi)存數(shù)據(jù),于是就可以直接讀取主線程里的內(nèi)存數(shù)據(jù),并將數(shù)據(jù)寫(xiě)入到 RDB 文件。
當(dāng)主線程對(duì)這些共享的內(nèi)存數(shù)據(jù)也都是只讀操作,那么,主線程和 bgsave 子進(jìn)程相互不影響。
但是,如果主線程要修改共享數(shù)據(jù)里的某一塊數(shù)據(jù)(比如鍵值對(duì) A
)時(shí),就會(huì)發(fā)生寫(xiě)時(shí)復(fù)制,于是這塊數(shù)據(jù)的物理內(nèi)存就會(huì)被復(fù)制一份(鍵值對(duì) A'
),然后主線程在這個(gè)數(shù)據(jù)副本(鍵值對(duì) A'
)進(jìn)行修改操作。與此同時(shí),bgsave 子進(jìn)程可以繼續(xù)把原來(lái)的數(shù)據(jù)(鍵值對(duì) A
)寫(xiě)入到 RDB 文件。
就是這樣,Redis 使用 bgsave 對(duì)當(dāng)前內(nèi)存中的所有數(shù)據(jù)做快照,這個(gè)操作是由 bgsave 子進(jìn)程在后臺(tái)完成的,執(zhí)行時(shí)不會(huì)阻塞主線程,這就使得主線程同時(shí)可以修改數(shù)據(jù)。
細(xì)心的同學(xué),肯定發(fā)現(xiàn)了,bgsave 快照過(guò)程中,如果主線程修改了共享數(shù)據(jù),發(fā)生了寫(xiě)時(shí)復(fù)制后,RDB 快照保存的是原本的內(nèi)存數(shù)據(jù),而主線程剛修改的數(shù)據(jù),是被辦法在這一時(shí)間寫(xiě)入 RDB 文件的,只能交由下一次的 bgsave 快照。
所以 Redis 在使用 bgsave 快照過(guò)程中,如果主線程修改了內(nèi)存數(shù)據(jù),不管是否是共享的內(nèi)存數(shù)據(jù),RDB 快照都無(wú)法寫(xiě)入主線程剛修改的數(shù)據(jù),因?yàn)榇藭r(shí)主線程的內(nèi)存數(shù)據(jù)和子線程的內(nèi)存數(shù)據(jù)已經(jīng)分離了,子線程寫(xiě)入到 RDB 文件的內(nèi)存數(shù)據(jù)只能是原本的內(nèi)存數(shù)據(jù)。
如果系統(tǒng)恰好在 RDB 快照文件創(chuàng)建完畢后崩潰了,那么 Redis 將會(huì)丟失主線程在快照期間修改的數(shù)據(jù)。
另外,寫(xiě)時(shí)復(fù)制的時(shí)候會(huì)出現(xiàn)這么個(gè)極端的情況。
在 Redis 執(zhí)行 RDB 持久化期間,剛 fork 時(shí),主進(jìn)程和子進(jìn)程共享同一物理內(nèi)存,但是途中主進(jìn)程處理了寫(xiě)操作,修改了共享內(nèi)存,于是當(dāng)前被修改的數(shù)據(jù)的物理內(nèi)存就會(huì)被復(fù)制一份。
那么極端情況下,如果所有的共享內(nèi)存都被修改,則此時(shí)的內(nèi)存占用是原先的 2 倍。
所以,針對(duì)寫(xiě)操作多的場(chǎng)景,我們要留意下快照過(guò)程中內(nèi)存的變化,防止內(nèi)存被占滿了。
四、RDB 和 AOF 合體
盡管 RDB 比 AOF 的數(shù)據(jù)恢復(fù)速度快,但是快照的頻率不好把握:
如果頻率太低,兩次快照間一旦服務(wù)器發(fā)生宕機(jī),就可能會(huì)比較多的數(shù)據(jù)丟失; 如果頻率太高,頻繁寫(xiě)入磁盤(pán)和創(chuàng)建子進(jìn)程會(huì)帶來(lái)額外的性能開(kāi)銷(xiāo)。
那有沒(méi)有什么方法不僅有 RDB 恢復(fù)速度快的優(yōu)點(diǎn)和,又有 AOF 丟失數(shù)據(jù)少的優(yōu)點(diǎn)呢?
當(dāng)然有,那就是將 RDB 和 AOF 合體使用,這個(gè)方法是在 Redis 4.0 提出的,該方法叫混合使用 AOF 日志和內(nèi)存快照,也叫混合持久化。
如果想要開(kāi)啟混合持久化功能,可以在 Redis 配置文件將下面這個(gè)配置項(xiàng)設(shè)置成 yes:
aof-use-rdb-preamble yes
混合持久化工作在 AOF 日志重寫(xiě)過(guò)程。
當(dāng)開(kāi)啟了混合持久化時(shí),在 AOF 重寫(xiě)日志時(shí),fork
出來(lái)的重寫(xiě)子進(jìn)程會(huì)先將與主線程共享的內(nèi)存數(shù)據(jù)以 RDB 方式寫(xiě)入到 AOF 文件,然后主線程處理的操作命令會(huì)被記錄在重寫(xiě)緩沖區(qū)里,重寫(xiě)緩沖區(qū)里的增量命令會(huì)以 AOF 方式寫(xiě)入到 AOF 文件,寫(xiě)入完成后通知主進(jìn)程將新的含有 RDB 格式和 AOF 格式的 AOF 文件替換舊的的 AOF 文件。
也就是說(shuō),使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量數(shù)據(jù),后半部分是 AOF 格式的增量數(shù)據(jù)。

這樣的好處在于,重啟 Redis 加載數(shù)據(jù)的時(shí)候,由于前半部分是 RDB 內(nèi)容,這樣加載的時(shí)候速度會(huì)很快。
加載完 RDB 的內(nèi)容后,才會(huì)加載后半部分的 AOF 內(nèi)容,這里的內(nèi)容是 Redis 后臺(tái)子進(jìn)程重寫(xiě) AOF 期間,主線程處理的操作命令,可以使得數(shù)據(jù)更少的丟失。
以上就是淺談Redis RDB快照的詳細(xì)內(nèi)容,更多關(guān)于Redis RDB的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- Redis 徹底禁用RDB持久化操作
- Redis 通過(guò) RDB 方式進(jìn)行數(shù)據(jù)備份與還原的方法
- Redis持久化RDB和AOF區(qū)別詳解
- Redis打開(kāi)rdb文件常用方法詳解
- redis學(xué)習(xí)之RDB、AOF與復(fù)制時(shí)對(duì)過(guò)期鍵的處理教程
- Redis兩種持久化方案RDB和AOF詳解
- 了解redis中RDB結(jié)構(gòu)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- Redis RDB技術(shù)底層原理詳解