天天看點

redis持久化機制,深入分析redisAOF和RDB模式的利弊

文章目錄

  • ​​寫在前面​​
  • ​​日志檔案-AOF​​
  • ​​AOF的格式​​
  • ​​AOF的寫入方式​​
  • ​​三種寫回政策​​
  • ​​AOF 中開啟 always 刷盤政策也會存在資料丢失嗎?​​
  • ​​AOF配置為每秒刷盤,有可能阻塞Redis,影響性能嗎?​​
  • ​​AOF日志太大的弊端​​
  • ​​AOF重寫​​
  • ​​AOF重寫對主線程的影響性​​
  • ​​AOF 重寫過程中其他潛在的阻塞風險​​
  • ​​關于Huge page​​
  • ​​AOF重寫的過程​​
  • ​​AOF重寫的時候,如果重寫緩沖區滿了,怎麼處理?​​
  • ​​AOF 重寫能共享使用 AOF 本身的日志嗎​​
  • ​​記憶體快照-RDB​​
  • ​​給哪些資料做快照​​
  • ​​生成快照時需要資料靜止嗎​​
  • ​​寫時複制(Copy-On-Write)​​
  • ​​為啥RDB 要 fork 子程序而不是線程?​​
  • ​​如果上一次生成RDB快照還沒執行完,又觸發了持久化政策,這個時候是順序執行等上一次持久化完成?還是并行處理?​​
  • ​​關于Copy On write問題:資料持久化fork子程序時,子程序不會一次copy所有資料,而是在修改時觸發Copy On write。假設主線程中有1000條資料,fork建立子程序後,主線程有請求新增了100條,修改了200條,這些記憶體是如何在主程序和子程序配置設定的?​​
  • ​​那fork期間會阻塞父程序嗎?為什麼會阻塞?​​
  • ​​RDB寫入的時候,通過主線程fork出bgsave子程序時,進行寫入RDB檔案,此時主線程也可以接受的寫操作,那麼主線程接收新的寫操作,bgsave子程序還會再把這個資料,寫入到RDB檔案嗎?​​
  • ​​子程序做RDB期間,父程序寫入新資料,父程序做Copy On Write申請新的記憶體,那子程序完成RDB後,程序退出,記憶體回收是怎樣的?​​
  • ​​記憶體快照的缺點​​
  • ​​AOF+RDB混合模式​​
  • ​​開啟混合持久化,在恢複時加載 RDB 檔案和 AOF 的順序是怎樣的​​
  • ​​Redis【混合持久化】,具體持久化的資料格式是怎樣的?​​
  • ​​如何區分rdb和aof的分界?​​
  • ​​參考資料​​

寫在前面

我們都知道,Redis是一個記憶體資料庫,資料儲存在記憶體中,通路速度是相當快的。

但是記憶體中的資料,伺服器每次重新開機之後就會丢失,redis是如何做到持久化的呢?redis持久化設計有哪些巧妙之處呢?

目前,Redis 的持久化主要有兩大機制,即 AOF(Append Only File)日志和 RDB 快照。

日志檔案-AOF

AOF的格式

redis的AOF是一種日志檔案,不像mysql的redo log(重做日志),記錄的是修改後的二進制資料, AOF 裡記錄的是 Redis 收到的每一條指令,這些指令是以文本形式儲存的。

我們以 Redis 收到“set testkey testvalue”指令後記錄的日志為例,看看 AOF 日志的内容。其中,“*3”表示目前指令有三個部分,每部分都是由“$+數字”開頭,後面緊跟着具體的指令、鍵或值。這裡,“數字”表示這部分中的指令、鍵或值一共有多少位元組。例如,“$3 set”表示這部分有 3 個位元組,也就是“set”指令。

redis持久化機制,深入分析redisAOF和RDB模式的利弊

AOF的寫入方式

AOF 裡記錄的是 Redis 收到的每一條指令,這些指令是以文本形式儲存的,也就是說每一條指令都會生成一條AOF日志。

那麼假如說這條指令是文法有誤的指令呢?也會記錄嗎?

Redis 是先執行指令,把資料寫入記憶體,然後才記錄日志,如下圖所示:

redis持久化機制,深入分析redisAOF和RDB模式的利弊

文法有問題的指令當然不會寫入AOF日志,但是如果寫入AOF時再額外檢查文法的話,就會有一些額外的開銷。

為了避免額外的檢查開銷,Redis 在向 AOF 裡面記錄日志的時候,并不會先去對這些指令進行文法檢查。是以,如果先記日志再執行指令的話,日志中就有可能記錄了錯誤的指令,Redis 在使用日志恢複資料時,就可能會出錯。是以AOF采用先執行指令後寫日志的方式——寫後日志。

而寫後日志這種方式,就是先讓系統執行指令,隻有指令能執行成功,才會被記錄到日志中,否則,系統就會直接向用戶端報錯。是以,Redis 使用寫後日志這一方式的一大好處是,可以避免出現記錄錯誤指令的情況。

除此之外,AOF寫後日志還有一個好處:它是在指令執行後才記錄日志,是以不會阻塞目前的寫操作。

不過,redis的AOF寫後日志是有風險的:

① 如果剛執行完一個指令,還沒有來得及記日志就當機了,那麼這個指令和相應的資料就有丢失的風險。如果此時 Redis 是用作緩存,還可以從後端資料庫重新讀入資料進行恢複,但是,如果 Redis 是直接用作資料庫的話,此時,因為指令沒有記入日志,是以就無法用日志進行恢複了。

② AOF 雖然避免了對目前指令的阻塞,但可能會給下一個操作帶來阻塞風險。這是因為,AOF 日志也是在主線程中執行的,如果在把日志檔案寫入磁盤時,磁盤寫壓力大,就會導緻寫盤很慢,進而導緻後續的操作也無法執行了。

那麼有解決以上問題的方案嗎?有。

三種寫回政策

redis有三種寫AOF的方式:

  • Always,同步寫回:每個寫指令執行完,立馬同步地将日志寫回磁盤;
  • Everysec,每秒寫回:每個寫指令執行完,隻是先把日志寫到 AOF 檔案的記憶體緩沖區,每隔一秒把緩沖區中的内容寫入磁盤;
  • No,作業系統控制的寫回:每個寫指令執行完,隻是先把日志寫到 AOF 檔案的記憶體緩沖區,由作業系統決定何時将緩沖區内容寫回磁盤。

但是這三種寫回方式都是有弊端的:

  • “同步寫回”可以做到基本不丢資料,但是它在每一個寫指令後都有一個慢速的落盤操作,不可避免地會影響主線程性能;
  • “每秒寫回”采用一秒寫回一次的頻率,避免了“同步寫回”的性能開銷,雖然減少了對系統性能的影響,但是如果發生當機,上一秒内未落盤的指令操作仍然會丢失。是以,這隻能算是,在避免影響主線程性能和避免資料丢失兩者間取了個折中;
  • “作業系統控制的寫回”在寫完緩沖區後,就可以繼續執行後續的指令,不會有阻塞的過程,但是落盤的時機已經不在 Redis 手中了,隻要 AOF 記錄沒有寫回磁盤,一旦當機對應的資料就丢失了。
redis持久化機制,深入分析redisAOF和RDB模式的利弊

AOF 中開啟 always 刷盤政策也會存在資料丢失嗎?

可能會。Redis 是先操作記憶體,後寫AOF磁盤日志。比如 Redis 記憶體執行完了,去刷盤的時候當機了就會導緻資料丢失。

AOF配置為每秒刷盤,有可能阻塞Redis,影響性能嗎?

有可能的。

AOF 配置為每秒刷盤,具體邏輯是這樣的:

1、Redis 主線程把指令寫到 AOF page cache(調用 write 系統調用)

2、Redis 背景線程每間隔 1 秒,把 AOF page cache 持久化到磁盤(調用 fsync 系統調用)

如果 2 執行時,遲遲沒有成功,那麼 1 執行時就會阻塞住,原因是在操作同一個 fd 時,fsync 和 write互斥的,一方必須等待另一方完成。

步驟 2 執行不成功的原因在于:機器的磁盤 IO 負載非常高(可能有别的程式在瘋狂寫磁盤,把磁盤帶寬占滿了),此時 1 在執行時,就會阻塞等待,進而影響到了主線程,進而影響整個 Redis 性能。

具體可參見 Redis 源碼 aof.c,搜尋:Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.

redis持久化機制,深入分析redisAOF和RDB模式的利弊

AOF日志太大的弊端

随着接收的寫指令越來越多,AOF 檔案就會不可避免的越來越大。

AOF檔案太大必然會影響性能:

① 檔案系統本身對檔案大小有限制,無法儲存過大的檔案;

② 如果檔案太大,之後再往裡面追加指令記錄的話,效率也會變低;

③ 如果發生當機,AOF 中記錄的指令要一個個被重新執行,用于故障恢複,如果日志檔案太大,整個恢複過程就會非常緩慢,這就會影響到 Redis 的正常使用。

怎麼處理AOF檔案過大的問題呢?——AOF重寫機制。

AOF重寫

簡單來說,AOF 重寫機制就是在重寫時,Redis 根據資料庫的現狀建立一個新的 AOF 檔案,也就是說,讀取資料庫中的所有鍵值對,然後對每一個鍵值對用一條指令記錄它的寫入。比如說,當讀取了鍵值對“testkey”: “testvalue”之後,重寫機制會記錄 set testkey testvalue 這條指令。這樣,當需要恢複時,可以重新執行該指令,實作“testkey”: “testvalue”的寫入。

AOF重寫結果其實就是 對舊日志檔案中的多條指令,在重寫後的新日志中變成了一條指令。

AOF 檔案是以追加的方式,逐一記錄接收到的寫指令的。當一個鍵值對被多條寫指令反複修改時,AOF 檔案會記錄相應的多條指令。但是,在重寫的時候,是根據這個鍵值對目前的最新狀态,為它生成對應的寫入指令。這樣一來,一個鍵值對在重寫日志中隻用一條指令就行了,而且,在日志恢複時,隻用執行這條指令,就可以直接完成這個鍵值對的寫入了。

redis持久化機制,深入分析redisAOF和RDB模式的利弊

如上圖,redis在不斷對資料進行操作時,其實多條指令操作一條資料之後的結果,可以将這多條指令合并,這樣在AOF檔案中隻記錄一個最終結果即可。這樣可以大大的縮小AOF檔案的大小。

AOF重寫對主線程的影響性

AOF重寫會影響到redis的主線程嗎?

AOF日志是由主線程寫的,但是AOF重寫的 過程是由背景子程序 bgrewriteaof 來完成的,這也是為了避免阻塞主線程,導緻資料庫性能下降。

AOF 重寫過程中其他潛在的阻塞風險

這裡有兩個風險。

風險一:

Redis 主線程 fork 建立 bgrewriteaof 子程序時,核心需要建立用于管理子程序的相關資料結構,這些資料結構在作業系統中通常叫作程序控制塊(Process Control Block,簡稱為 PCB)。核心要把主線程的 PCB 内容拷貝給子程序。這個建立和拷貝過程由核心執行,是會阻塞主線程的。而且,在拷貝過程中,子程序要拷貝父程序的頁表,這個過程的耗時和 Redis 執行個體的記憶體大小有關。如果 Redis 執行個體記憶體大,頁表就會大,fork 執行時間就會長,這就會給主線程帶來阻塞風險。

a、fork子程序,fork這個瞬間一定是會阻塞主線程的(注意,fork時并不會一次性拷貝所有記憶體資料給子程序,老師文章寫的是拷貝所有記憶體資料給子程序,我個人認為是有歧義的),fork采用作業系統提供的寫實複制(Copy On Write)機制,就是為了避免一次性拷貝大量記憶體資料給子程序造成的長時間阻塞問題,但fork子程序需要拷貝程序必要的資料結構,其中有一項就是拷貝記憶體頁表(虛拟記憶體和實體記憶體的映射索引表),這個拷貝過程會消耗大量CPU資源,拷貝完成之前整個程序是會阻塞的,阻塞時間取決于整個執行個體的記憶體大小,執行個體越大,記憶體頁表越大,fork阻塞時間越久。拷貝記憶體頁表完成後,子程序與父程序指向相同的記憶體位址空間,也就是說此時雖然産生了子程序,但是并沒有申請與父程序相同的記憶體大小。那什麼時候父子程序才會真正記憶體分離呢?“寫實複制”顧名思義,就是在寫發生時,才真正拷貝記憶體真正的資料,這個過程中,父程序也可能會産生阻塞的風險,就是下面介紹的場景。

b、fork出的子程序指向與父程序相同的記憶體位址空間,此時子程序就可以執行AOF重寫,把記憶體中的所有資料寫入到AOF檔案中。但是此時父程序依舊是會有流量寫入的,如果父程序操作的是一個已經存在的key,那麼這個時候父程序就會真正拷貝這個key對應的記憶體資料,申請新的記憶體空間,這樣逐漸地,父子程序記憶體資料開始分離,父子程序逐漸擁有各自獨立的記憶體空間。因為記憶體配置設定是以頁為機關進行配置設定的,預設4k,如果父程序此時操作的是一個bigkey,重新申請大塊記憶體耗時會變長,可能會産阻塞風險。另外,如果作業系統開啟了記憶體大頁機制(Huge Page,頁面大小2M),那麼父程序申請記憶體時阻塞的機率将會大大提高,是以在Redis機器上需要關閉Huge Page機制。Redis每次fork生成RDB或AOF重寫完成後,都可以在Redis log中看到父程序重新申請了多大的記憶體空間。      

風險二:

bgrewriteaof 子程序會和主線程共享記憶體。當主線程收到新寫或修改的操作時,主線程會申請新的記憶體空間,用來儲存新寫或修改的資料,如果操作的是 bigkey,也就是資料量大的集合類型資料,那麼,主線程會因為申請大空間而面臨阻塞風險。因為作業系統在配置設定記憶體空間時,有查找和鎖的開銷,這就會導緻阻塞。

也就是說,AOF重寫不複用AOF本身的日志,一個原因是父子程序寫同一個檔案必然會産生競争問題,控制競争就意味着會影響父程序的性能。二是如果AOF重寫過程中失敗了,那麼原本的AOF檔案相當于被污染了,無法做恢複使用。是以Redis AOF重寫一個新檔案,重寫失敗的話,直接删除這個檔案就好了,不會對原先的AOF檔案産生影響。等重寫完成之後,直接替換舊檔案即可。

關于Huge page

Huge page對提升TLB命中率比較友好,因為在相同的記憶體容量下,使用huge page可以減少頁表項,TLB就可以緩存更多的頁表項,能減少TLB miss的開銷。

但是,這個機制對于Redis這種喜歡用fork的系統來說,的确不太友好,尤其是在Redis的寫入請求比較多的情況下。因為fork後,父程序修改資料采用寫時複制,複制的粒度為一個記憶體頁。如果隻是修改一個256B的資料,父程序需要讀原來的記憶體頁,然後再映射到新的實體位址寫入。一讀一寫會造成讀寫放大。如果記憶體頁越大(例如2MB的大頁),那麼讀寫放大也就越嚴重,對Redis性能造成影響。

Huge page在實際使用Redis時是建議關掉的。

AOF重寫的過程

AOF重寫的過程:

每次執行重寫時,主線程 fork 出背景的 bgrewriteaof 子程序。此時,fork 會把主線程的記憶體拷貝一份給 bgrewriteaof 子程序,這裡面就包含了資料庫的最新資料。然後,bgrewriteaof 子程序就可以在不影響主線程的情況下,逐一把拷貝的資料寫成操作,記入重寫日志。

AOF重寫的日志記錄:

1、因為主線程未阻塞,仍然可以處理新來的操作。此時,如果有寫操作,第一處日志就是指正在使用的 AOF 日志,Redis 會把這個操作寫到它的緩沖區。這樣一來,即使當機了,這個 AOF 日志的操作仍然是齊全的,可以用于恢複。

2、而第二處日志,就是指新的 AOF 重寫日志。這個操作也會被寫到重寫日志的緩沖區。這樣,重寫日志也不會丢失最新的操作。等到拷貝資料的所有操作記錄重寫完成後,重寫日志記錄的這些最新操作也會寫入新的 AOF 檔案,以保證資料庫最新狀态的記錄。此時,我們就可以用新的 AOF 檔案替代舊檔案了。

redis持久化機制,深入分析redisAOF和RDB模式的利弊

總結來說,每次 AOF 重寫時,Redis 會先執行一個記憶體拷貝,用于重寫;然後,使用兩個日志保證在重寫過程中,新寫入的資料不會丢失。而且,因為 Redis 采用額外的線程進行資料重寫,是以,這個過程并不會阻塞主線程。

AOF重寫的時候,如果重寫緩沖區滿了,怎麼處理?

重寫緩沖區會滿嗎?滿了會放棄本次重寫嗎?

AOF重寫緩沖區不會滿,是個連結清單,隻要記憶體不超過設定的maxmemory。

如果超過maxmemory,執行配置的淘汰政策。

AOF 重寫能共享使用 AOF 本身的日志嗎

顯然是不能的。如果都用 AOF 日志的話,主線程要寫,bgrewriteaof 子程序也要寫,這兩者會競争檔案系統的鎖,這就會對 Redis 主線程的性能造成影響。

記憶體快照-RDB

所謂記憶體快照,就是指記憶體中的資料在某一個時刻的狀态記錄。

對 Redis 來說,RDB(Redis DataBase) 它實作類似照片記錄效果的方式,把某一時刻的狀态以檔案的形式寫到磁盤上,即使當機,快照檔案也不會丢失,資料的可靠性也就得到了保證。

RDB 記錄的是某一時刻的資料,是以,在做資料恢複時,我們可以直接把 RDB 檔案讀入記憶體,很快地完成恢複。

給哪些資料做快照

Redis 的資料都在記憶體中,為了提供所有資料的可靠性保證,它執行的是全量快照,也就是說,需要把記憶體中的所有資料都記錄到磁盤中。

那麼問題來了,生成快照的時候,需要redis主線程阻塞嗎?

給記憶體的全量資料做快照,把它們全部寫入磁盤也會花費很多時間。而且,全量資料越多,RDB 檔案就越大,往磁盤上寫資料的時間開銷就越大。

Redis 提供了兩個指令來生成 RDB 檔案,分别是 save 和 bgsave。

  • save:在主線程中執行,會導緻阻塞;
  • bgsave:建立一個子程序,專門用于寫入 RDB 檔案,避免了主線程的阻塞,這也是 Redis RDB 檔案生成的預設配置。

就像給人拍照一樣,拍照的時候攝影師都會要求大家保持一個表情不動,那麼redis生成RDB的時候需要保持資料靜止嗎?

生成快照時需要資料靜止嗎

生成快照并不是一瞬間生成的,肯定是所有的資料逐漸生成的。

那麼,在生成快照時,需要資料全部靜止嗎(不允許寫)?

舉個例子。我們在時刻 t 給記憶體做快照,假設記憶體資料量是 4GB,磁盤的寫入帶寬是 0.2GB/s,簡單來說,至少需要 20s(4/0.2 = 20)才能做完。如果在時刻 t+5s 時,一個還沒有被寫入磁盤的記憶體資料 A,被修改成了 A’,那麼就會破壞快照的完整性,因為 A’不是時刻 t 時的狀态。

但是,如果快照執行期間資料不能被修改,那無疑就會給業務服務造成巨大的影響。

寫時複制(Copy-On-Write)

簡單來說,bgsave 子程序是由主線程 fork 生成的,可以共享主線程的所有記憶體資料。bgsave 子程序運作後,開始讀取主線程的記憶體資料,并把它們寫入 RDB 檔案。

此時,如果主線程對這些資料也都是讀操作(例如圖中的鍵值對 A),那麼,主線程和 bgsave 子程序互相不影響。但是,如果主線程要修改一塊資料(例如圖中的鍵值對 C),那麼,這塊資料就會被複制一份,生成該資料的副本(鍵值對 C’)。然後,主線程在這個資料副本上進行修改。同時,bgsave 子程序可以繼續把原來的資料(鍵值對 C)寫入 RDB 檔案。

redis持久化機制,深入分析redisAOF和RDB模式的利弊

這既保證了快照的完整性,也允許主線程同時對資料進行修改,避免了對正常業務的影響。

Redis 會使用 bgsave 對目前記憶體中的所有資料做快照,這個操作是子程序在背景完成的,這就允許主線程同時可以修改資料。

為啥RDB 要 fork 子程序而不是線程?

1、先想一下RDB的目的是什麼?就是把記憶體資料持久化到磁盤上,而且隻持久化截止某一時刻的資料即可,不關心之後的資料怎麼改(記憶體快照)

2、性能:如果用子線程做的話,主線程寫,其他線程讀,然後子線程資料寫磁盤,有資源競争,需要加鎖,加鎖會降低Redis性能,而且在實作上很複雜,成本高。

3、基于以上考慮,fork一個子程序來搞,最經濟,成本也最低。因為fork子程序,作業系統把這些事都做好了,有記憶體快照資料,沒有鎖競争,子程序怎麼寫磁盤也不會影響父程序,還有COW不影響主程序寫資料,一舉多得。

如果上一次生成RDB快照還沒執行完,又觸發了持久化政策,這個時候是順序執行等上一次持久化完成?還是并行處理?

等上一次RDB執行完,才能觸發執行下一次RDB。

關于Copy On write問題:資料持久化fork子程序時,子程序不會一次copy所有資料,而是在修改時觸發Copy On write。假設主線程中有1000條資料,fork建立子程序後,主線程有請求新增了100條,修改了200條,這些記憶體是如何在主程序和子程序配置設定的?

1、首先要了解 Copy On Write 含義:即寫時複制,誰寫誰複制

2、fork子程序,此時的子程序和父程序會指向相同的位址空間,當父程序有新的寫請求進來,它想要修改資料,那麼它就把需要修改的key的記憶體,拷貝一份出來,再修改這塊新記憶體的資料,此時父程序記憶體位址就會指向這個新申請的記憶體空間

3、在這期間,子程序不會修改任何資料,是以不會配置設定任何新的記憶體,它依舊指向父程序那些資料的記憶體位址空間,這個過程是作業系統層面做好的。

那fork期間會阻塞父程序嗎?為什麼會阻塞?

1、fork完成之前,會阻塞父程序,主要是父程序需要拷貝程序中的記憶體頁表給子程序,每個程序都要有自己的記憶體頁表,是以這個父子程序無法共享,必須要拷貝一份

2、拷貝記憶體頁表也需要花費時間,程序占用的記憶體越大,拷貝時間越久

RDB寫入的時候,通過主線程fork出bgsave子程序時,進行寫入RDB檔案,此時主線程也可以接受的寫操作,那麼主線程接收新的寫操作,bgsave子程序還會再把這個資料,寫入到RDB檔案嗎?

不會。RDB的目的是,隻要一份記憶體快照,即隻要fork那一瞬間,父程序所擁有的資料,fork完成後子程序指向父程序的所有記憶體資料位址空間,是以就與父程序共享資料了,此時子程序把這些資料scan出來,持久化到磁盤就可以了,不需要關心父程序有沒有寫入新資料。

子程序做RDB期間,父程序寫入新資料,父程序做Copy On Write申請新的記憶體,那子程序完成RDB後,程序退出,記憶體回收是怎樣的?

子程序退出時,如果它指向的記憶體資料,沒有被父程序修改過(對于這塊資料,父程序沒有做COW),那麼這塊記憶體資料,還是歸父程序所有,子程序不會回收。

如果在子程序RDB期間,父程序有新資料寫入或修改,對一部分key的記憶體做了COW,那這些key的記憶體,父子程序各自獨立,子程序退出時,就會回收它指向的這些記憶體空間。

記憶體快照的缺點

1、兩次記憶體快照期間伺服器當機時,此時新的資料沒來得及儲存快照,會造成資料丢失。

2、性能問題:

① 頻繁将全量資料寫入磁盤,會給磁盤帶來很大壓力,多個快照競争有限的磁盤帶寬,前一個快照還沒有做完,後一個又開始做了,容易造成惡性循環。

② bgsave 子程序需要通過 fork 操作從主線程建立出來。雖然,子程序在建立後不會再阻塞主線程,但是,fork 這個建立過程本身會阻塞主線程,而且主線程的記憶體越大,阻塞時間越長。如果頻繁 fork 出 bgsave 子程序,這就會頻繁阻塞主線程了(是以,在 Redis 中如果有一個 bgsave 在運作,就不會再啟動第二個 bgsave 子程序)。

AOF+RDB混合模式

AOF+RDB混合模式就是,記憶體快照以一定的頻率執行,在兩次快照之間,使用 AOF 日志記錄這期間的所有指令操作。

這樣一來,快照不用很頻繁地執行,這就避免了頻繁 fork 對主線程的影響。而且,AOF 日志也隻用記錄兩次快照間的操作,也就是說,不需要記錄所有操作了,是以,就不會出現檔案過大的情況了,也可以避免重寫開銷。

redis持久化機制,深入分析redisAOF和RDB模式的利弊

開啟混合持久化,在恢複時加載 RDB 檔案和 AOF 的順序是怎樣的

準确來說,混合持久化隻是對 AOF rewrite 做的優化。

因為 AOF 寫入很長時間後,檔案體積會變得非常大,為了優化檔案大小,Redis提出了 AOF rewrite,即檔案增長一定門檻值(可配置),則自動重寫這個 AOF 檔案,以達到縮小檔案體積的目的。

後來到 Redis 4.0,又進一步做了優化,就是混合持久化。

就是在 AOF rewrite 時,先寫一個 RDB 進去,再把在這期間産生的寫指令,追加到 AOF 檔案中。

在 AOF 檔案中,前面是一個 RDB 格式的資料,後面是 AOF 格式的資料。

這樣一來,這個 AOF 檔案體積就更小了。

Redis【混合持久化】,具體持久化的資料格式是怎樣的?

一個 Redis 要想開啟混合持久化,必須這樣配置:1.開啟AOF 2.配置AOF rewrite 3.配置AOF rewrite 開啟混合持久化,缺一不可。

重點:混合持久化是對 AOF rewrite 的進一步優化。

然後,從最簡單的說起,一個空Redis,開始寫入資料,資料做持久化,會是這樣:

假設寫入了 100 條指令,那 AOF 中記錄的就是這 100 條指令

假設現在觸發了 AOF rewrite 的門檻值,需要對 AOF 進行瘦身,因為開啟了【混合持久化】,那 Redis 會掃描整個執行個體,把整個執行個體中的資料,生成一個 RDB,寫到 AOF 中 (RDB 是二進制資料)

在寫 RDB 到 AOF 檔案期間,Redis 依舊會收到寫操作,假設這段時間收到了 10 條寫指令,那這 10 條指令會等 RDB 寫完成後,再依次追加到 AOF 中,此時 AOF 中的資料就是 RDB + 10 條寫指令

之後 Redis 繼續收到寫操作,假設收到 5 條寫指令,那也依次追加到 AOF 中,此時 AOF 中就是一個 RDB + 10 + 5 條寫指令

繼續寫操作,繼續追加 AOF,如果此時 AOF 又觸發到了需要 rewrite 的門檻值,那就繼續走 2-3-4 步驟。

如何區分rdb和aof的分界?

再次觸發aof重寫時候,如何處理的?會不會生成新的檔案?rdb+10+5已經存在的資料如何處理

參考資料