Redis持久化使用及說明(RDB&AOF)
Redis(數(shù)據(jù)存儲在內(nèi)存中)支持 RDB 和 AOF 兩種持久化(和 MySQL 里的持久性是一回事,把數(shù)據(jù)存儲在硬盤上,重啟進(jìn)程 / 主機(jī)后數(shù)據(jù)仍然存在 —— 持久;把數(shù)據(jù)存儲在內(nèi)存上,重啟進(jìn)程 / 主機(jī)后數(shù)據(jù)消失 —— 不持久)機(jī)制,持久化功能有效地避免因進(jìn)程退出造成數(shù)據(jù)丟失問題,當(dāng)下次重啟時利用之前持久化的文件即可實現(xiàn)數(shù)據(jù)恢復(fù)。
Redis 為了保證速度快,數(shù)據(jù)肯定還得存儲在內(nèi)存中。但是為了持久化,數(shù)據(jù)還得想辦法存儲在硬盤上。所以,最后決定在內(nèi)存中和硬盤上都存儲數(shù)據(jù),這樣的兩份數(shù)據(jù)在理論上(實際上可能存在一個小的概率有差異,具體取決于如何進(jìn)行持久化)是完全相同的。當(dāng)要插入一個新的數(shù)據(jù)時,就需要把這個數(shù)據(jù)同時寫入到內(nèi)存和硬盤。當(dāng)查詢某個數(shù)據(jù)時,直接從內(nèi)存中讀取,硬盤的數(shù)據(jù)只是在 Redis 重啟時,用來恢復(fù)內(nèi)存中的數(shù)據(jù)。代價就是消耗了更多的空間,同一份數(shù)據(jù)存儲了兩遍,但畢竟硬盤價格便宜,開銷不會帶來太大的成本。而且實際上具體怎么寫硬盤還有不同的策略,是可以保證整體的效率足夠高的。
假設(shè)我自己的電腦上有很多的學(xué)習(xí)資料,雖然現(xiàn)在是把這些學(xué)習(xí)資料保存在硬盤上(持久化保存),但是萬一我的電腦出現(xiàn)故障(相較于 CPU、顯卡、內(nèi)存來說,硬盤是最容易出問題的,尤其是機(jī)械硬盤)。可以拿另一塊移動硬盤來作為備份用的硬盤:
- 定期備份(每個月將電腦硬盤上的學(xué)習(xí)資料整體的備份到這個備份盤中)—— RDB
- 實時備份(只要下載了一個新的學(xué)習(xí)資料,就立即把這份學(xué)習(xí)資料往備份盤中拷貝一份)—— AOF
一、RDB
RDB(Redis DataBase)持久化是把定期的將當(dāng)前的進(jìn)程數(shù)據(jù)生成快照保存到硬盤的過程,觸發(fā) RDB 持久化過程分為手動觸發(fā)和自動觸發(fā)。
1、觸發(fā)機(jī)制
手動觸發(fā)分別對應(yīng) save 和 bgsave 命令:
- save 命令:阻塞當(dāng)前 Redis 服務(wù)器,直到 RDB 過程完成為止,對于內(nèi)存比較大的實例造成長時間阻塞。(一半不建議使用)
- bgsave(background save)命令:Redis 進(jìn)程執(zhí)行 fork 操作創(chuàng)建子進(jìn)程,RDB 持久化過程由子進(jìn)程負(fù)責(zé),完成后自動結(jié)束。阻塞只發(fā)生在 fork 階段,一般時間很短。不會影響 Redis 服務(wù)器處理其他客戶端的請求和命令。(此處 Redis 使用的是 “多進(jìn)程” 的方式來完成的并發(fā)編程,來完成 bgsave 的實現(xiàn))
Redis 內(nèi)部的所有涉及 RDB 的操作都采用類似 bgsave 的方式。
如果插入新的 key,而此時不手動執(zhí)行 bgsave,直接重新啟動 Redis 服務(wù)器,那么剛剛插入的數(shù)據(jù)在重啟之后仍然存在。所以說,Redis 生成快照操作不僅僅是手動執(zhí)行命令才觸發(fā),也可以自動觸發(fā),也就是下面的第 3 點。
除了手動觸發(fā)之外,Redis 運行自動觸發(fā) RDB 持久化機(jī)制,這個觸發(fā)機(jī)制才是在實戰(zhàn)中有價值的。
- 使用 save 配置。如 "save m n" 表示 m 秒內(nèi)數(shù)據(jù)集發(fā)生了 n 次修改,自動 RDB 持久化。
- 從節(jié)點進(jìn)行全量復(fù)制(主從復(fù)制)操作時,主節(jié)點自動進(jìn)行 RDB 持久化生成快照,隨后將 RDB 快照文件內(nèi)容發(fā)送給從節(jié)點。
- 如果執(zhí)行 shutdown 命令(service redis-server restart,正常關(guān)閉)關(guān)閉 Redis 時,或者通過正常流程重新啟動 Redis 服務(wù)器,那么此時 Redis 服務(wù)器會在退出時自動執(zhí)行 RDB 持久化。但如果是異常重啟(kill -9 或者服務(wù)器掉電),那么此時 Redis 服務(wù)器來不及生成 rdb,內(nèi)存中尚未保存到快照中的數(shù)據(jù),就會隨著重啟而丟失。

并不是說 Redis 客戶端這邊插入了數(shù)據(jù),rdb 文件中的數(shù)據(jù)就會立即更新的。插入幾個鍵值對后,沒有運行手動觸發(fā)的命令,也達(dá)不到自動觸發(fā)的條件,那么就不會更新。
如果修改成如下內(nèi)容:

對于 Redis 來說,配置文件發(fā)生修改后,一定要重新啟動服務(wù)器才能生效。(當(dāng)然,如果想要立即生效,也可以通過命令的方式進(jìn)行修改)

同時滿足兩個條件即可觸發(fā)快照的生成:

如果是修改成以下內(nèi)容:

那么將會關(guān)閉自動生成快照這個功能。
如果把 rdb 文件故意改壞會怎么樣?
手動把 rdb 文件內(nèi)容改壞,如果是通過 service redis-server restart 重啟,就會在 Redis 服務(wù)器退出時重新生成 rdb 快照,那么剛才改壞的文件就會被替換掉。
而如果是通過 kill 進(jìn)程的方式,再重新啟動 Redis 服務(wù)器,此時 rdb 文件就還是錯的。但看起來 Redis 好像沒有受到什么影響,還是能正常啟動,能正確獲取到 key。那是因為剛才修改的位置應(yīng)該正好是文件的末尾,對前面的內(nèi)容沒有什么影響。但如果是修改了中間位置的內(nèi)容,那么 Redis 服務(wù)器就啟動不了了。
此時,Redis 服務(wù)器掛了,可以看看 Redis 日志,了解一下發(fā)生了什么。

打開該文件,可以看到:

也就是在 rdb 恢復(fù)數(shù)據(jù)的過程中出現(xiàn)了問題。
rdb 文件是二進(jìn)制的,如果直接把壞了的 rdb 文件交給 Redis 服務(wù)器去使用,那么得到的結(jié)果是不可預(yù)期的。
所以,Redis 也提供了 rdb 文件的檢查工具,可以先通過檢查工具來檢查一下 rdb 文件格式是否符合要求。

5.0 版本中,檢查工具和 Redis 服務(wù)器是同一個可執(zhí)行程序,可以在運行時加入不同的選項,從而使用其中不同的功能。
運行時加入 rdb 文件作為命令行參數(shù),那么此時就是以檢查工具的方式來運行,不會真的啟動 Redis 服務(wù)器。

2、流程說明
bgsave 是主流的 RDB 持久化方式,根據(jù)下圖來了解它的運作流程。
bgsave 命令的運作流程:

- 執(zhí)行 bgsave 命令,Redis 父進(jìn)程(Redis 服務(wù)器)判斷當(dāng)前進(jìn)是否存在其他正在執(zhí)行的子進(jìn)程,比如:RDB / AOF 子進(jìn)程,如果存在 bgsave 命令直接返回。
- 如果沒有其它的工作子進(jìn)程,父進(jìn)程通過執(zhí)行 fork 這樣的系統(tǒng)調(diào)用來創(chuàng)建一個子進(jìn)程(該場景中的絕大部分內(nèi)存數(shù)據(jù)是不需要改變的,所以在短時間內(nèi)父進(jìn)程中不會有大批的內(nèi)存數(shù)據(jù)變化,因此子進(jìn)程的 “寫時拷貝” 并不會觸發(fā)很多次),fork 過程中父進(jìn)程會阻塞,通過 info stats 命令查看 latest_fork_usec 選項,可以獲取最近一次 fork 操作的耗時,單位為微秒。
- 父進(jìn)程 fork 完成后,bgsave 命令返回 "Background saving started" 信息,并不再阻塞父進(jìn)程,可以繼續(xù)響應(yīng)其他命令。
- 子進(jìn)程創(chuàng)建 RDB 文件,根據(jù)父進(jìn)程內(nèi)存生成臨時快照文件,完成后對原有文件進(jìn)行原子替換。執(zhí)行 lastsave 命令可以獲取最后一次生成 RDB 的時間,對應(yīng) info 統(tǒng)計的 rdb_last_save_time 選項。
- 進(jìn)程發(fā)送信號給父進(jìn)程表示完成,父進(jìn)程更新統(tǒng)計信息,子進(jìn)程就可以結(jié)束銷毀了。
bgsave 操作流程是創(chuàng)建子進(jìn)程,子進(jìn)程完成持久化操作(持久化速度太快了(數(shù)據(jù)少),難以觀察到子進(jìn)程),持久化會把數(shù)據(jù)寫入到新的文件中,然后使用新的文件替換舊的文件(這個容易觀察)。
可以通過 Linux 的 stat 命令來查看文件的 inode 編號:



這兩個文件不再是同一個文件了,只不過文件內(nèi)容是一樣的。inode 編號就相當(dāng)于文件的身份標(biāo)識。如果是直接使用 save 命令,那么此時是不會觸發(fā)子進(jìn)程和文件替換邏輯的,會直接在當(dāng)前進(jìn)程中往剛才的同一文件中寫入數(shù)據(jù)。
文件系統(tǒng)典型的組織方式(ext4)主要是把整個文件系統(tǒng)分成三個大的部分:
- 超級塊(存放一些管理信息)
- inode 區(qū)(存放 inode 節(jié)點,每個文件都會分配一個 inode 數(shù)據(jù)結(jié)構(gòu),包含文件的各種元數(shù)據(jù))
- block 區(qū)(存放文件的數(shù)據(jù)內(nèi)容)
3、RDB 文件的處理
保存:RDB 文件(把內(nèi)存中的數(shù)據(jù)以壓縮(需要消耗一定的 cpu 資源,但是能節(jié)省存儲空間)的形式保存到這個二進(jìn)制文件中)保存在 dir 配置指定的目錄(默認(rèn) /var/lib/redis/)下,文件名通過 dbfilename 配置(默認(rèn) dump.rdb)指定。
可以通過執(zhí)行 config set dir {newDir} 和 config set dbfilename {newFilename} 運行期間動態(tài)執(zhí)行,當(dāng)下次運行時 RDB 文件會保存到新目錄。


- 壓縮:Redis 默認(rèn)采用 LZF 算法對生成的 RDB 文件做壓縮處理,壓縮后的文件遠(yuǎn)遠(yuǎn)小于內(nèi)存大小,默認(rèn)開啟,可以通過參數(shù) config set rdbcompression {yes|no} 動態(tài)修改。
雖然壓縮 RDB 會消耗 CPU,但可以大幅降低文件的體積,方便保存到硬盤或通過網(wǎng)絡(luò)發(fā)送到從節(jié)點,因此建議開啟。
- 校驗:如果 Redis 啟動時加載到損壞的 RDB 文件會拒絕啟動。這時可以使用 Redis 提供的 redis-check-dump 工具檢測 RDB 文件并獲取對應(yīng)的錯誤報告。
當(dāng)執(zhí)行生成 rdb 鏡像操作時,此時就會把要生成的快照數(shù)據(jù)先保存到一個臨時文件中。當(dāng)這個快照生成完畢后,再刪除之前的 rdb 文件,把新生成的臨時 rdb 文件名改成剛才的 dump.rdb。也就保證了,rdb 文件自始至終只有一個。
執(zhí)行 flushall 命令會自動情況 rdb 文件。
4、RDB 的優(yōu)缺點
(1)優(yōu)點
- RDB 是?個緊湊壓縮的二進(jìn)制文件,代表 Redis 在某個時間點上的數(shù)據(jù)快照。非常適用于備份,全量復(fù)制等場景。比如每 6 小時執(zhí)行 bgsave 備份,并把 RDB 文件復(fù)制到遠(yuǎn)程機(jī)器或者文件系統(tǒng)中(如 hdfs)用于災(zāi)備。
- Redis 加載 RDB 恢復(fù)數(shù)據(jù)遠(yuǎn)遠(yuǎn)快于 AOF 的方式。 (二進(jìn)制的方式則直接將數(shù)據(jù)讀取到內(nèi)存中,按照字節(jié)的格式取出來放到結(jié)構(gòu)體 / 對象即可,文本方式組織數(shù)據(jù)則需要進(jìn)行一系列的字符串切分操作)
(2)缺點
- RDB 方式數(shù)據(jù)沒辦法做到實時持久化 / 秒級持久化(在兩次生成快照之間,實時數(shù)據(jù)可能會隨著重啟而丟失),這就導(dǎo)致快照里的數(shù)據(jù)和當(dāng)前實時的數(shù)據(jù)情況可能存在偏差。因為 bgsave 每次運行都要執(zhí)行 fork 創(chuàng)建子進(jìn)程,屬于重量級操作,頻繁執(zhí)行成本過高。
- RDB 文件使用特定二進(jìn)制格式保存,Redis 版本演進(jìn)過程中有多個 RDB 版本,兼容性可能有風(fēng)險(舊版本的 Redis 的 rdb 文件放到新版本的 Redis 中不一定能實現(xiàn)。但一般來說,實際工作中 Redis 版本都是統(tǒng)一的,實在不行也可以通過寫一個程序的方式來直接遍歷舊的 Redis 中的所有 key,把數(shù)據(jù)取出來插入到新的 Redis 服務(wù)器中即可)。
二、AOF
AOF(Append Only File)持久化(類似于 MySQL 中的 binlog,會把用戶的每個操作都記錄到文件中):以獨立日志的方式記錄每次寫命令,重啟時再重新執(zhí)行 AOF 文件中的命令達(dá)到恢復(fù)數(shù)據(jù)的目的。AOF 的主要作用是解決了數(shù)據(jù)持久化的實時性,目前已經(jīng)是 Redis 持久化的主流方式。
Redis 重新啟動時,又讀 RDB、又讀 AOF,到底以哪個為準(zhǔn)呢?
當(dāng)開啟 AOF 時,rdb 就不生效了,啟動的時候就不再讀取 rdb 文件內(nèi)容。
1、使用 AOF
開啟 AOF 功能需要設(shè)置配置:appendonly yes,默認(rèn)是關(guān)閉狀態(tài)。AOF 文件名通過 appendfilename 配置(默認(rèn)是 appendonly.aof)設(shè)置。


保存目錄同 RDB 持久化方式一致,通過 dir 配置指定(/var/lib/redis)。AOF 的工作流程操作:命令寫入(append)、文件同步(sync)、文件重寫(rewrite)、重啟加載(load),如下圖所示:
AOF 工作流程:

- 所有的寫入命令會追加到 aof_buf(內(nèi)存中的緩沖區(qū),大大降低了寫硬盤的次數(shù))中。
- AOF 緩沖區(qū)根據(jù)對應(yīng)的策略向硬盤做同步操作。
- 隨著 AOF 文件越來越大,需要定期對 AOF 文件進(jìn)行重寫,達(dá)到壓縮的目的。
- 當(dāng) Redis 服務(wù)器啟動時,可以加載 AOF 文件進(jìn)行數(shù)據(jù)恢復(fù)。
注意:寫硬盤的時候,寫入硬盤數(shù)據(jù)的多少對于性能的影響不是很大,但是寫入硬盤的次數(shù)則影響很大了。
硬盤上讀寫數(shù)據(jù),順序讀寫的速度還是比較快的(但還是比內(nèi)存要慢很多),隨機(jī)訪問則速度比較慢。AOF 是每次將新的數(shù)據(jù)寫入到原有文件的末尾,屬于順序?qū)懭搿?/p>
2、命令寫入
AOF 命令寫入的內(nèi)容直接是文本協(xié)議格式。

每次進(jìn)行的操作都會被記錄到文本文件中,通過一些特殊符號作為分隔符,來對命令的細(xì)節(jié)做出區(qū)分。


此處遵守 Redis 格式協(xié)議,Redis 選擇文本協(xié)議可能的原因:
- 文本協(xié)議具備較好的兼容性。
- 實現(xiàn)簡單。
- 具備可讀性。
AOF 過程中為什么需要 aof_buf 這個緩沖區(qū)?
Redis 雖然是使用單線程響應(yīng)命令,但是速度很快,因為它只是操作內(nèi)存。引入 AOF 之后,又要寫內(nèi)存,又要寫硬盤,同時還要保持之前的速度。實際上,這并沒有影響到 Redis 處理請求的速度。
AOF 機(jī)制并非是直接讓工作線程把數(shù)據(jù)寫入硬盤,而是先寫入一個內(nèi)存中的緩沖區(qū),積累一波之后再統(tǒng)一寫入。如果每次寫 AOF 文件都直接同步硬盤,性能從內(nèi)存的讀寫變成 IO 讀寫,必然會下降。先寫入緩沖區(qū)可以有效減少 IO 次數(shù),同時,Redis 還可以提供多種緩沖區(qū)同步(刷新)策略,讓用戶根據(jù)自己的實際情況和需求來做出合理的平衡。
如果把數(shù)據(jù)寫入到緩沖區(qū)中,其本質(zhì)還是在內(nèi)存中。萬一此時突然進(jìn)程掛了或者主機(jī)掉點了,那緩沖區(qū)中的數(shù)據(jù)是否就丟了呢?
是的。緩沖區(qū)中沒來得及寫入硬盤的數(shù)據(jù)是會丟失的。
- 緩沖區(qū)刷新頻率越高,性能影響就越大,同時數(shù)據(jù)的可靠性就越高。
- 緩沖區(qū)刷新頻率越低,性能影響就越小,同時數(shù)據(jù)的可靠性就越低。
3、文件同步
Redis 提供了多種 AOF 緩沖區(qū)同步文件策略,由參數(shù) appendfsync 控制,不同值的含義如下表所示。
AOF 緩沖區(qū)同步文件策略:

默認(rèn)采用 everysec 配置:

系統(tǒng)調(diào)用 write 和 fsync 說明:
- write 操作會觸發(fā)延遲寫(delayed write)機(jī)制。Linux 在內(nèi)核提供頁緩沖區(qū)用來提供硬盤 IO 性能。write 操作在寫入系統(tǒng)緩沖區(qū)后立即返回。同步硬盤操作依賴于系統(tǒng)調(diào)度機(jī)制,例如:緩沖區(qū)頁空間寫滿或達(dá)到特定時間周期。同步文件之前,如果此時系統(tǒng)故障宕機(jī),緩沖區(qū)內(nèi)數(shù)據(jù)將丟失。
- Fsync 針對單個文件操作,做強(qiáng)制硬盤同步,fsync 將阻塞直到數(shù)據(jù)寫入到硬盤。
- 配置為 always 時,每次寫入都要同步 AOF 文件,性能很差,在?般的 SATA 硬盤上,只能?持大約幾百 TPS 寫入。除非是非常重要的數(shù)據(jù),否則不建議配置。
- 配置為 no 時,由于操作系統(tǒng)同步策略不可控,雖然提高了性能,但數(shù)據(jù)丟失風(fēng)險大增,除非數(shù)據(jù)重要程度很低,一般不建議配置。
- 配置為 everysec,是默認(rèn)配置,也是推薦配置,兼顧了數(shù)據(jù)安全性和性能。理論上最多丟失 1s 的數(shù)據(jù)。
4、重寫機(jī)制
隨著命令不斷寫入 AOF,文件持續(xù)增長,體積會越來越大,會影響到 Redis 下次啟動的啟動時間(Redis 在啟動時需要讀取 AOF 文件內(nèi)容,該文件記錄了中間的過程,但實際上 Redis 在重啟時只關(guān)注最終結(jié)果)。
為了解決這個問題,Redis 引入 AOF 重寫機(jī)制(能夠針對 AOF 文件進(jìn)行整理操作,剔除其中的冗余操作并合并一些操作,以此達(dá)到給文件 “瘦身” 的效果)壓縮文件體積。
AOF 文件重寫是把 Redis 進(jìn)程內(nèi)的數(shù)據(jù)轉(zhuǎn)化為寫命令同步到新的 AOF 文件。

重寫后的 AOF 為什么可以變???
- 進(jìn)程內(nèi)已超時的數(shù)據(jù)不再寫入文件。
- 舊的 AOF 中的無效命令,例如 del、hdel、srem 等重寫后將會刪除,只需要保留數(shù)據(jù)的最終版本。
- 多條寫操作合并為?條,例如 lpush list a、lpush list b、lpush list 從可以合并為 lpush list a b c。
較小的 AOF 文件一方面降低了硬盤空間占用,一方面可以提升啟動 Redis 時數(shù)據(jù)恢復(fù)的速度。
AOF 重寫過程可以手動觸發(fā)和自動觸發(fā):
- 手動觸發(fā):調(diào)用 bgrewriteaof 命令。
- 自動觸發(fā):根據(jù) auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 參數(shù)確定自動觸發(fā)時機(jī)。
- auto-aof-rewrite-min-size:表示觸發(fā)重寫時 AOF 的最小文件大小,默認(rèn)為 64MB。
- auto-aof-rewrite-percentage:代表當(dāng)前 AOF 占用大小相比較上次重寫時增加的比例。
當(dāng)觸發(fā) AOF 重寫時,下圖介紹它的運行流程。
AOF 重寫流程:

- 執(zhí)行 AOF 重寫請求。如果當(dāng)前進(jìn)程正在執(zhí)行 AOF 重寫,請求不執(zhí)行。如果當(dāng)前進(jìn)程正在執(zhí)行 bgsave 操作,重寫命令延遲到 bgsave 完成之后再執(zhí)行。
- 父進(jìn)程執(zhí)行 fork 創(chuàng)建子進(jìn)程。
- 重寫。a. 父進(jìn)程 fork 之后,繼續(xù)響應(yīng)其他命令,仍然負(fù)責(zé)接收客戶端的新的請求。父進(jìn)程還是會把這些請求產(chǎn)生的 AOF 數(shù)據(jù)先寫入到緩沖區(qū)中并根據(jù) appendfsync 策略同步到硬盤,保證舊 AOF 文件機(jī)制正確。b. 子進(jìn)程只有 fork 之前的所有內(nèi)存信息,父進(jìn)程中需要將 fork 之后這段時間的修改操作寫入 AOF 重寫緩沖區(qū)中。重寫的時候不關(guān)心 AOF 文件中原來有什么,只關(guān)心內(nèi)存中最終的數(shù)據(jù)狀態(tài)。(內(nèi)存中的數(shù)據(jù)的狀態(tài),就已經(jīng)相當(dāng)于是把 AOF 文件結(jié)果整理后的模樣了)
- 在創(chuàng)建子進(jìn)程的一瞬間,子進(jìn)程就根據(jù)內(nèi)存快照,將命令合并到新的 AOF 文件中,也就是繼承了當(dāng)前父進(jìn)程的內(nèi)存狀態(tài)。因此,子進(jìn)程里的內(nèi)存數(shù)據(jù)是父進(jìn)程 fork 之前的狀態(tài)。fork 后新來的請求對內(nèi)存造成的修改是子進(jìn)程感知不到的。此時,父進(jìn)程這里又準(zhǔn)備了一個 aof_rewrite_buf 緩沖區(qū)(專門存放 fork 后收到的數(shù)據(jù))。
- 子進(jìn)程完成重寫:
子進(jìn)程這邊把 AOF 新文件數(shù)據(jù)寫入完成后,子進(jìn)程會通過發(fā)送信號通知父進(jìn)程。
父進(jìn)程再把 aof_rewrite_buf 緩沖區(qū)中的內(nèi)容也追加到新 AOF 文件里。
用新 AOF 文件代替舊 AOF 文件。
此處子進(jìn)程寫數(shù)據(jù)的過程非常類似于 RDB 生成一個鏡像快照,只不過 RDB 是按照二進(jìn)制的方式來生成的,AOF 重寫則是按照 AOF 這里要求的文本格式來生成的。二者目的都是為了把當(dāng)前內(nèi)存中的所有數(shù)據(jù)狀態(tài)記錄到文件中。
如果在執(zhí)行 bgrewriteaof 的時候,發(fā)現(xiàn)當(dāng)前 Redis 已經(jīng)正在進(jìn)行 AOF 重寫了,會怎樣呢?
此時不會再次執(zhí)行 AOF 重寫,而是直接返回了。
如果在執(zhí)行 bgrewriteaof 的時候,發(fā)現(xiàn)當(dāng)前 Redis 在生成 rdb 文件的快照,會怎樣呢?
此時 AOF 重寫操作就會等待 rdb 快照生成完畢之后再進(jìn)行執(zhí)行 AOF 重寫。
為什么 RDB 對于 fork 之后的新數(shù)據(jù)就直接置之不理了呢,而不選擇采用和 AOF 一樣的處理機(jī)制呢?
RDB 本身的設(shè)計理念就是用來 “定期備份” 的。只要是定期備份就難以和最新數(shù)據(jù)保持一致。
實時備份不一定就比定期備份更好,具體還是要看實際場景需求?,F(xiàn)在的系統(tǒng)中,系統(tǒng)資源一般都是比較充裕的,AOF 的開銷并不大,所以一般來說,AOF 的適用場景更多一些。
父進(jìn)程 fork 完畢之后,就已經(jīng)讓子進(jìn)程寫新的 AOF 文件了。并且隨著時間的推移,子進(jìn)程很快就寫完了新的文件,要讓新的 AOF 文件代替舊的 AOF 文件。父進(jìn)程此時還在繼續(xù)寫這個即將消亡的舊的 AOF 文件是否還有意義呢?
需要考慮到極端情況:假設(shè)在重寫的過程中,重寫了一半服務(wù)器突然掛了,此時子進(jìn)程內(nèi)存的數(shù)據(jù)就會丟失,新的 AOF 文件內(nèi)容還不完整,所以如果父進(jìn)程不堅持寫舊的 AOF 文件,那么重啟就無法保證數(shù)據(jù)的完整性了。




AOF 本來是按照文本的方式來寫入文件的,但是文本的方式來寫文件,后續(xù)加載的成本較高。所以,Redis 就引入了 “混合持久化” 的方式,結(jié)合了 rdb 和 aof 的特點。
按照 aof 的方式,將每一個請求 / 操作都記錄入文件中。在觸發(fā) aof 重寫之后,就會把當(dāng)前內(nèi)存的狀態(tài)按照 rdb 的二進(jìn)制格式寫入到新的 aof 文件中。

后續(xù)再進(jìn)行的操作仍然是按照 aof 文本的方式追加到文件后面:


5、啟動時數(shù)據(jù)恢復(fù)
當(dāng) Redis 啟動時,會根據(jù) RDB 和 AOF 文件的內(nèi)容,進(jìn)行數(shù)據(jù)恢復(fù),如下圖所示。
Redis 根據(jù)持久化文件進(jìn)行數(shù)據(jù)恢復(fù):

三、RDB 和 AOF 的區(qū)別和聯(lián)系
- RDB 和 AOF 是 Redis 提供了兩種持久化方案。
- RDB 視為內(nèi)存的快照,產(chǎn)生的內(nèi)容更為緊湊,占用空間較小,恢復(fù)時速度更快。但產(chǎn)? RDB 的開銷較大,不適合進(jìn)行實時持久化,一般用于冷備和主從復(fù)制。
- AOF 視為對修改命令保存,在恢復(fù)時需要重放命令,并且有重寫機(jī)制來定期壓縮 AOF 文件。
- RDB 和 AOF 都使用 fork 創(chuàng)建子進(jìn)程,利用 Linux 子進(jìn)程擁有父進(jìn)程內(nèi)存快照的特點進(jìn)行持久化,盡可能不影響主進(jìn)程繼續(xù)處理后續(xù)命令。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
kubernetes環(huán)境部署單節(jié)點redis數(shù)據(jù)庫的方法
這篇文章主要介紹了kubernetes環(huán)境部署單節(jié)點redis數(shù)據(jù)庫的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
詳談redis跟數(shù)據(jù)庫的數(shù)據(jù)同步問題
文章討論了在Redis和數(shù)據(jù)庫數(shù)據(jù)一致性問題上的解決方案,主要比較了先更新Redis緩存再更新數(shù)據(jù)庫和先更新數(shù)據(jù)庫再更新Redis緩存兩種方案,文章指出,刪除Redis緩存后再更新數(shù)據(jù)庫的方案更優(yōu),因為它可以避免數(shù)據(jù)不一致的問題,但可能產(chǎn)生高并發(fā)問題2025-01-01
Redis報錯NOAUTH?Authentication?required簡單解決辦法
這篇文章主要給大家介紹了關(guān)于Redis報錯NOAUTH?Authentication?required的簡單解決辦法,Redis無密碼報錯NOAUTH Authentication required的原因是客戶端訪問Redis時需要提供密碼,但是沒有提供或提供的密碼不正確,需要的朋友可以參考下2024-05-05

