最新資訊:Redis 中的持久化是如何進(jìn)行的?

發(fā)布時間:2023-03-10 17:38:24  |  來源:騰訊網(wǎng)  

◆ 前言

我們知道 Redis 是內(nèi)存數(shù)據(jù)庫,所有操作都在內(nèi)存上完成。內(nèi)存的話,服務(wù)器斷電,內(nèi)存上面的數(shù)據(jù)就會丟失了。這個問題顯然是需要解決的。


【資料圖】

Redis 中引入了持久化來避免數(shù)據(jù)的丟失,主要有兩種持久化的方式 RDB 持久化和 AOF 持久化。

◆?AOF 持久化

什么是 AOF 持久化

AOF(Append Only File):通過保存數(shù)據(jù)庫執(zhí)行的命令來記錄數(shù)據(jù)庫的狀態(tài)。

AOF日志對數(shù)據(jù)庫命令的保存順序是,Redis 先執(zhí)行命令,把數(shù)據(jù)寫入內(nèi)存,然后才記錄日志。

為什么要后記錄日志呢

1、后寫,能夠避免記錄到錯誤的命令。因?yàn)槭窍葓?zhí)行命令,后寫入日志,只有命令執(zhí)行成功了,命令才能被寫入到日志中。

2、避免阻塞當(dāng)前的寫操作,是在命令執(zhí)行后才記錄日志,所以不會阻塞當(dāng)前的寫操作。

AOF 的潛在風(fēng)險

1、如果命令執(zhí)行成功,寫入日志的時候宕機(jī)了,命令沒有寫入到日志中,這時候就有丟失數(shù)據(jù)的風(fēng)險了,因?yàn)檫@時候沒有寫入日志,服務(wù)斷電之后,這部分?jǐn)?shù)據(jù)就丟失了。

這種場景在別的地方也很常見,比如基于 MQ 實(shí)現(xiàn)分布式事務(wù),也會出現(xiàn)這種場景,RabbitMQ,RocketMQ,Kafka 事務(wù)性,消息丟失和消息重復(fù)發(fā)送的處理策略

2、AOF 的日志寫入也是在主線程進(jìn)行的,如果磁盤的壓力很大,寫入速度變慢了,會影響后續(xù)的操作。

這兩種情況可通過調(diào)整 AOF 文件的寫入磁盤的時機(jī)來避免

AOF 文件的寫入和同步

AOF 文件持久化的功能分成三個步驟,文件追加(append),文件寫入,文件同步(sync)。

AOF 文件在寫入磁盤之前是先寫入到 aof_buf 緩沖區(qū)中,然后通過調(diào)用 flushAppendOnlyFile 將緩沖區(qū)中的內(nèi)容保存到 AOF 文件中。

寫入的策略通過 appendfsync 來進(jìn)行配置

Always:同步寫回 每次寫操作命令執(zhí)行完后,同步將 AOF 日志數(shù)據(jù)寫回硬盤;

Everysec:每秒寫回 每次寫操作命令執(zhí)行完后,先將命令寫入到 AOF 文件的內(nèi)核緩沖區(qū),然后每隔一秒將緩沖區(qū)里的內(nèi)容寫回到硬盤;

No:操作系統(tǒng)控制的寫回 Redis 不在控制命令的寫會時機(jī),交由系統(tǒng)控制。每次寫操作命令執(zhí)行完成之后,命令會被放入到 AOF 文件的內(nèi)核緩沖區(qū),之后什么時候?qū)懭氲酱疟P,交由系統(tǒng)控制。

AOF 文件重寫機(jī)制

因?yàn)槊看螆?zhí)行的命令都會被寫入到 AOF 文件中,隨著系統(tǒng)的運(yùn)行,越來越多的文件會被寫入到 AOF 文件中,這樣 AOF 文件勢必會變得很大,這種情況該如何去處理呢?

為了解決這種情況,Redis 中引入了重寫的機(jī)制

什么是重寫呢?

因?yàn)?AOF 文件中記錄的是每個命令的操作記錄,舉個,比如當(dāng)一個鍵值對被多條寫命令反復(fù)修改時,AOF文件會記錄相應(yīng)的多條命令,那么重寫機(jī)制,就是根據(jù)這個鍵值對當(dāng)前的最新狀態(tài),為它生成對應(yīng)的寫入命令,保存成一行操作命令。這樣就精簡了 AOF 文件的大小。

簡單來講就是多變一,就是把 AOF 中日志根據(jù)當(dāng)前鍵值的狀態(tài),合并成一條操作命令。

重寫之后的文件會保存到新的 AOF 文件中,這時候舊的 AOF 文件和新的 AOF 文件中鍵值對的狀態(tài)是一樣的。然后新的 AOF 文件會替換掉舊的 AOF 文件,這樣 重寫操作一直在進(jìn)行,AOF 文件就不至于變的過大。

重寫是后臺進(jìn)行的, AOF 的重寫會放到子進(jìn)程中進(jìn)行的,使用子進(jìn)程的優(yōu)點(diǎn):

1、子進(jìn)程處理 AOF 期間,不會影響 Redis 主線程對數(shù)據(jù)的處理;

2、子進(jìn)程擁有所在線程的數(shù)據(jù)副本,使用進(jìn)程能夠避免鎖的使用,保證數(shù)據(jù)的安全。

這里來看下,AOF 的處理流程

AOF 重寫也有一個緩沖區(qū),當(dāng)服務(wù)節(jié)接收到新的命令的是,如果在正在進(jìn)行 AOF 重寫,命令同樣也會被發(fā)送到 AOF 緩沖區(qū)

子進(jìn)程執(zhí)行 AOF 重寫的過程,服務(wù)端進(jìn)程主要處理以下內(nèi)容

1、接收并處理客戶端發(fā)送的命令;

2、將執(zhí)行后的命令寫入到 AOF 緩沖區(qū);

3、將執(zhí)行后的命令也寫入到 AOF 重寫緩沖區(qū);

AOF 緩沖區(qū)和 AOF 重寫緩沖區(qū)中的內(nèi)容會被定期的同步到 AOF 文件和 AOF 重寫文件中

當(dāng)子進(jìn)程完成重寫的時候,會給父進(jìn)程發(fā)送一個信號,這時候父進(jìn)程主要主要進(jìn)行下面的兩步操作:

1、將 AOF 重寫緩沖區(qū)中的內(nèi)容全部寫入到 AOF 重寫文件中,這時候重寫 AOF 文件保存的數(shù)據(jù)狀態(tài)是和服務(wù)端數(shù)據(jù)庫的狀態(tài)一致的;

2、將 AOF 重寫文件替換舊的 AOF 文件;

通過 AOF 的重寫操作,新的 AOF 文件不斷的替換舊的 AOF 文件,這樣就能控制 AOF 文件的大小

AOF 的數(shù)據(jù)還原

AOF 文件包了重建數(shù)據(jù)庫索引鎖需要的全部命令,所以只需要讀入并重新執(zhí)行一遍 AOF 文件中保存的命令,即可還原服務(wù)關(guān)閉之前數(shù)據(jù)庫的狀態(tài)。

◆?RDB 持久化

什么是 RDB 持久化

RDB(Redis database):實(shí)現(xiàn)方式是將存在 Redis 內(nèi)存中的數(shù)據(jù)寫入到 RDB 文件中保存到磁盤上從而實(shí)現(xiàn)持久化的。

和 AOF 不同的是 RDB 保存的是數(shù)據(jù)而不是操作,在進(jìn)行數(shù)據(jù)恢復(fù)的時候,直接把 RDB 的文件讀入到內(nèi)存,即可完成數(shù)據(jù)恢復(fù)。

RDB 如何做內(nèi)存快照

Redis 中對于如何備份數(shù)據(jù)到 RDB 文件中,提供了兩種方式

1、save: 在主線程中執(zhí)行,不過這種會阻塞 Redis 服務(wù)進(jìn)程;

2、bgsave: 主線程會 fork 出一個子進(jìn)程來負(fù)責(zé)處理 RDB 文件的創(chuàng)建,不會阻塞主線程的命令操作,這也是 Redis 中 RDB 文件生成的默認(rèn)配置;

對于 save 和 bgsave 這兩種快照方式,服務(wù)端是禁止這兩種方式同時執(zhí)行的,防止產(chǎn)生競爭條件。

Redis 中可以使用 save 選項,來配置服務(wù)端執(zhí)行 BGSAVE 命令的間隔時間

就是服務(wù)端在900秒,讀數(shù)據(jù)進(jìn)行了至少1次修改,就會觸發(fā)一次 BGSAVE 命令

就是服務(wù)端在300秒,讀數(shù)據(jù)進(jìn)行了至少10次修改,就會觸發(fā)一次 BGSAVE 命令

快照時發(fā)生數(shù)據(jù)修改

舉個栗子:我們在t時刻開始對內(nèi)存數(shù)據(jù)內(nèi)進(jìn)行快照,假定目前有 2GB 的數(shù)據(jù)需要同步,磁盤寫入的速度是??那么,快照的時間就是 20s,那就是在??完成快照。

如果在 t+6s 的時候修改一個還沒有寫入磁盤的內(nèi)存數(shù)據(jù) test 為 test-hello。那么就會破壞快照的完整性了,因?yàn)?t 時刻備份的數(shù)據(jù)已經(jīng)被修改了。當(dāng)然是希望在備份期間數(shù)據(jù)不能被修改。

如果不能被修改,就意味這在快照期間不能對數(shù)據(jù)進(jìn)行修改操作,就如上面的栗子,快照需要進(jìn)行20s,期間不允許處理數(shù)據(jù)更新操作,這顯然也是不合理的。

這里需要聊一下 bgsave 是可以避免阻塞,不過需要注意的是避免阻塞和正常讀寫操作是有區(qū)別的。避免阻塞主線程確實(shí)沒有阻塞可以處理讀操作,但是為了保護(hù)快照的完整性,是不能修改快照期間的數(shù)據(jù)的。

這里就需要引入一種新的處理方案,寫時復(fù)制技術(shù)(Copy-On-Write, COW),在執(zhí)行快照的同時,正常處理寫操作。

bgsave 子進(jìn)程是由主線程 fork 生成的,所以是可以共享主線程的內(nèi)存的,bgsave子進(jìn)程運(yùn)行后會讀取主線程中的內(nèi)存數(shù)據(jù),并且寫入到 RDB 文件中。

寫復(fù)制技術(shù)就是,如果主線程在內(nèi)存快照期間修改了一塊內(nèi)存,那么這塊內(nèi)存會被復(fù)制一份,生成該數(shù)據(jù)的副本,然后 bgsave 子進(jìn)程在把這段內(nèi)存寫入到 RDB 文件中。這樣就可以在快照期間進(jìn)行數(shù)據(jù)的修改了。

多久做一次快照

對于快照,如果做的太頻繁,可能會出現(xiàn)前一次快照還沒有處理完成,后面的快照數(shù)據(jù)馬上就進(jìn)來了,同時過于頻繁的快照也會增加磁盤的壓力。

如果間隔時間過久,服務(wù)器在兩次快照期間宕機(jī),丟失的數(shù)據(jù)大小會隨著快照間隔時間的增長而增加。

是否可以選擇增量式快照呢?選擇增量式快照,我們就需要記住每個鍵值對的狀態(tài),如果鍵值對很多,同樣也會引入很多內(nèi)存空間,這對于內(nèi)存資源寶貴的Redis來說,有些得不償失。

相較于 AOF 來對比,RDB 是會在數(shù)據(jù)恢復(fù)時,速度更快。但是 RDB 的內(nèi)存快照同步頻率不太好控制,過多過少都有問題。

Redis 4.0中提出了一個混合使用 AOF 日志和內(nèi)存快照的方法。簡單來說,內(nèi)存快照以一定的頻率執(zhí)行,在兩次快照之間,使用AOF日志記錄這期間的所有命令操作。

通過混合使用AOF日志和內(nèi)存快照的方法,RDB 快照的頻率不需要過于頻繁,在兩次 RDB 快照期間,使用 AOF 日志來記錄,這樣也不用考慮 AOF 的文件過大問題,在下一次 RDB 快照開始的時候就可以刪除 AOF 文件了。

◆?過期的鍵如何持久化

在生成 RDB 文件的過程中,如果一個鍵已經(jīng)過期,那么其不會被保存到 RDB 文件中。在載入 RDB 的時候,要分兩種情況:

1、如果 Redis 以主服務(wù)器的模式運(yùn)行,那么會對 RDB 中的鍵進(jìn)行時間檢查,過期的鍵不會被恢復(fù)到 Redis 中。

2、如果 Redis 以從服務(wù)器的模式運(yùn)行,那么 RDB 中所有的鍵都會被載入,忽略時間檢查。在從服務(wù)器與主服務(wù)器進(jìn)行數(shù)據(jù)同步的時候,從服務(wù)器的數(shù)據(jù)會先被清空,所以載入過期鍵不會有問題。

對于 AOF 來說,如果一個鍵過期了,那么不會立刻對 AOF 文件造成影響。因?yàn)?Redis 使用的是惰性刪除和定期刪除,只有這個鍵被刪除了,才會往 AOF 文件中追加一條 DEL 命令。在重寫 AOF 的過程中,程序會檢查數(shù)據(jù)庫中的鍵,已經(jīng)過期的鍵不會被保存到 AOF 文件中。

在運(yùn)行過程中,對于主從復(fù)制的 Redis,主服務(wù)器和從服務(wù)器對于過期鍵的處理也不相同:

1、對于主服務(wù)器,一個過期的鍵被刪除了后,會向從服務(wù)器發(fā)送 DEL 命令,通知從服務(wù)器刪除對應(yīng)的鍵;

2、從服務(wù)器接收到讀取一個鍵的命令時,即使這個鍵已經(jīng)過期,也不會刪除,而是照常處理這個命令;

3、從服務(wù)器接收到主服務(wù)器的 DEL 命令后,才會刪除對應(yīng)的過期鍵。

這樣保證了數(shù)據(jù)的一致性,一個鍵值對存在于主服務(wù)器,也必然存在于從服務(wù)器。

◆?總結(jié)

AOF

優(yōu)點(diǎn):AOF 中有三種策略可以進(jìn)行選擇,AOF 的默認(rèn)策略為每秒鐘 fsync 一次,在這種配置下,Redis 仍然可以保持良好的性能,并且就算發(fā)生故障停機(jī),也最多只會丟失一秒鐘的數(shù)據(jù)。

缺點(diǎn):AOF 文件體積一般情況下比 RDB 文件體積大,并且數(shù)據(jù)還原速度也慢于 RDB。

RDB

優(yōu)點(diǎn):可以快速恢復(fù)數(shù)據(jù),相比于 AOF 的順序,逐一執(zhí)行操作命令,效率更高;

缺點(diǎn):因?yàn)槭莾?nèi)存快照,頻率過快,過慢,都會有響應(yīng)的問題。過快,浪費(fèi)磁盤資源,會給磁盤造成壓力,過慢會存在較多數(shù)據(jù)丟失的問題。

Redis 4.0中提出了一個混合使用 AOF 日志和內(nèi)存快照的方法,如果想要保證數(shù)據(jù)不丟失,這是一個比較好的選擇;

如果允許分鐘級別的數(shù)據(jù)丟失,可以只使用RDB;

如果只用AOF,優(yōu)先使用 everysec 的配置選項,因?yàn)樗诳煽啃院托阅苤g取了一個平衡。

關(guān)鍵詞:

 

網(wǎng)站介紹  |  版權(quán)說明  |  聯(lián)系我們  |  網(wǎng)站地圖 

星際派備案號:京ICP備2022016840號-16 營業(yè)執(zhí)照公示信息版權(quán)所有 郵箱聯(lián)系:920 891 263@qq.com