AOF日誌與RDB快照

2022-10-09 18:33:08 字數 4103 閱讀 3059

我們知道 redis 會當作快取使用,因為redis是記憶體資料庫,它把後端資料庫中的資料儲存在記憶體中,然後直接從記憶體中讀取資料,響應速度非常快。但是一旦伺服器宕機,記憶體中的資料將全部丟失。所以對於 redis 來說,實現資料的持久化是至關重要的。

目前 redis 的持久化主要有兩大機制:aof日誌rdb快照。

那麼為什麼 aof 要先執行指令再記錄資料呢,因為 aof 日誌裡面記錄的是 redis 收到的每一條資訊,是以文字形式儲存的。redis 為了避免額外的檢查開銷,在向 aof 裡面記錄日誌的時候並不會進行語法檢查,所以如果先記錄日誌再執行命令的話,日誌中就可能記錄了錯誤的命令,導致使用日誌恢復資料時出錯。而使用寫後日誌會先讓系統執行命令,只有執行成功了才能被記錄到日誌中,可以避免記錄錯誤命令的情況。另外,aof 在執行完寫命令之後才記錄日誌,不會阻塞當前的寫操作。

以下是指令 set mykey abc 的 aof 日誌。

*3

$3set

$5mykey

$3abc

*3 代表當前命令有三個部分,每部分都是由 "$數字" 開頭,後面跟著具體的命令、鍵或者值。$3 set 代表這部分有三個位元組,也就是 "set" 命令。

2.1 寫回策略

但是 aof 也存在著風險,就是當指令執行完成之後,伺服器宕機了,沒有來得及將指令記錄到日誌當中,造成了資料丟失的風險,如果此時是使用 redis 來作為資料庫的話,就無法使用日誌來進行資料的恢復了。另外,aof 雖然避免了當前命令的阻塞,但是在將日誌檔案寫入磁碟的時候,磁碟壓力大導致寫盤很慢,造成阻塞。所以控制寫命令執行完後 aof 日誌寫回磁碟的時機非常重要。

那麼如何選擇使用哪種方式呢,需要對三種方式的優缺點進行對比。

always,同步寫回,命令執行完立馬同步日誌,基本上不會丟失資料,但是寫命令都有乙個慢速落盤的操作,無法避免對主線程的效能造成影響。

everysec,每秒寫回,每一秒寫回一次的頻率避免了同步寫回的效能開銷,但是如果發生宕機,上一秒未落盤的資料可能會造成丟失。

no:,作業系統控制寫回,在執行完寫緩衝區資料後,只要 aof 的記錄沒有寫回磁碟,發生宕機也會造成對於的資料丟失。

綜上,如果對資料可靠性沒有要求,想要獲得高效能就選擇 no 策略,如果對資料可靠性要求高就選擇 always 策略,如果允許資料造成一點丟失,又希望有高效能就選擇 everysec 策略。

2.2 重寫機制

aof 採用檔案的形式記錄接收到的所有命令,但是隨著接收到的命令越來越多,檔案也會越來越大,可能會帶來效能問題:檔案系統對檔案的大小有限制;檔案過大再追加命令記錄效率會變低;如果發生宕機,aof 中記錄的命令要乙個個被重新執行,檔案過大的話恢復過程就會很慢。

為了解決檔案越來越大的問題,aof 採用了重寫機制。

在重寫時,redis 根據資料庫的使用情況建立乙個新的 aof 檔案,讀取資料庫中的所有鍵值對,例如讀取鍵值對 "mykey" : "myvalue",重寫機制會記錄 "set mykey myvalue" 這條指令,這樣原來的多條指令就變為了一條指令存在新的 aof 檔案中。而且在重寫時,根據鍵值對的最新狀態,生成對應的寫入命令,這樣在日誌恢復時只需要執行這一條命令,就可以完成鍵值對的寫入了。

aof 的重寫過程是由後台執行緒 bgrewriteaof 完成,避免了主線程的阻塞。

aof 重寫的過程:當執行重寫的時候,主線程 fork 出後台的 bgrewriteaof 子程序,fork 會把主線程的記憶體拷貝乙份到 bgrewriteaof 子程序,bgrewriteaof 子程序在不影響主線程的情況下,逐一把拷貝的資料寫成操作,記入重寫日誌。因為主線程沒有被阻塞,如果有新的寫操作,redis 會將正在使用的 aof 日誌寫到緩衝區中,這樣即使宕機了 aof 日誌的操作仍然是完整的,可以用於恢復。aof 重寫日誌也會被寫到重寫日誌緩衝區,等到拷貝資料的所有操作記錄重寫完成後,重寫日誌就將這些最新的操作寫入新的 aof 檔案,來保證資料庫最新狀態的記錄。

簡單來說,aof 重寫的時候,redis 會執行乙個記憶體拷貝,用於重寫。然後使用兩個日誌保證在重寫的過程中,新寫入的資料不會丟失,redis 採用額外的程序進行資料重寫,所以不會造成主線程的阻塞。

redis的另一種持久化的方法:記憶體快照,把記憶體中資料的某一時刻的狀態以檔案的形式寫到磁碟上,也就是快照,這樣即使伺服器宕機了快照檔案也不會丟失,保證了資料的可靠性,而這個快照檔案就稱為rdb(redis database)檔案,一般存放在 dump.rdb 檔案中。

對哪些資料進行快照,在對資料做快照時,資料能不能修改,會不會造成執行緒阻塞,多久做一次快照是我們要關注的問題。

3.1 快照物件

使用 rdb 快照,我們給哪些資料做快照呢。實際上,redis 的資料都在記憶體中,為了保證資料的可靠性,redis 執行的是全量快照。把記憶體中所有資料的狀態都記錄到磁碟中,但是當記憶體的全量資料越多,rdb 檔案就越大,往磁碟寫資料的時間開銷就越大。

redis 提供了兩個命令來生成 rdb 檔案:s**ebgs**e

s**e:在主線程中執行,會導致阻塞。

bgs**e:建立乙個子程序,專門用於寫入 rdb 檔案,不會造成程序阻塞,是 redis rdb 檔案生成的預設配置。

3.2 寫時複製

如果我們在進行快照執行期間,資料被修改的話,那麼就可能會導致資料不一致,比如已經將某一時刻資料的狀態記錄下來了,但是還沒有被寫入磁碟的資料 hello,被修改成了 helloworld,那麼就會破壞快照的完整性。那麼 redis 為了快照而暫停寫操作是不支援的,所以 redis 就會借助作業系統提供的寫時複製技術(copy-on=write,cow),在執行快照的時候正常處理寫操作。

bgs**e 子程序由主線程 fork 生成的,可以共享主線程的所有資料,bgs**e 子程序執行後,開始讀取主線程中的資料,並寫入 rdb 檔案中。當主線程要修改資料時,資料會被複製乙份,生成副本資料,bgs**e 會把副本資料寫入到 rdb 檔案中。

3.3 增量快照

如果我們將快照時間設定的比較長的話,如果某一時刻服務發生了宕機,如果上一次快照剛執行,則資料丟失的不會太大,如果距離上次快照執行時間間隔很長,那麼可能會造成大量資料的丟失,所以設定快照的間隔時間非常重要。但是快照執行的時間也不能設定的太小了,因為頻繁的將全量資料寫入磁碟會給磁碟帶來很大的壓力。在主線程 fork 生成 bgs**e子程序時會對主線程造成阻塞,所以如果頻繁 fork 出 bgs**e,會頻繁的阻塞主線程。

使用增量快照可以避免每次全量快照的開銷,增量快照就是在做完第一次全量快照後,後續再做快照我們只需要將被修改的資料寫入快照檔案即可。但同樣我們也需要記住有哪些資料被修改了,需要我們使用額外的元資料資訊來記錄哪些資訊被修改了,帶來額外的空間開銷問題。如果修改的資料過多,引起空間開銷太大,對記憶體資源寶貴的 redis 來說不值得。

預設的快照設定:

dbfilename dump.rdb

s**e 900 1 #當有一條keys資料被改變時,900秒重新整理到磁碟一次

s**e 300 10 #當有10條keys資料被改變時,300秒重新整理到磁碟一次

s**e 60 10000 #當有10000條keys資料被改變時,60秒重新整理到磁碟一次

3.4 混合使用

redis 4.0提出了混合使用 aof 日誌 和 rdb 記憶體快照的方法。記憶體快照以一定的頻率執行,在兩次快照之間,使用 aof 日誌記錄這期間的所以命令操作。這樣快照就不需要很頻繁的執行,避免了 fork 對主線程的影響,aof 日誌也只記錄兩次快照間的操作,不需要記錄所有的操作了,不會出現檔案過大的情況。

RDB與AOF的區別

aof和rdb是兩種redis持久化的機制。rdb rdb是將支援當前資料的快照存成乙個資料檔案的持久化機制。1.在生成快照時,將當前程序fork出乙個子程序.2.然後再子程序中迴圈所有的資料,將資料寫入到二進位制檔案中。3.當子程序將快照寫入臨時檔案完畢後,用臨時檔案替換原來的快照檔案,然後子程序...

RDB 與 AOF 抉擇與對比

rdb的啟動優先順序低於aof的啟動優先順序,在宕機的情況下會優先啟動aof rdb使用二進位制的檔案作為快照,所以檔案的體積小點,aof則使用了檔案追加的方式,所以檔案的提及大一些 rdb的恢復速度快,aof的恢復速度慢一些 rdb檔案dump過程中若出現故障,那麼會丟失較多的資料,aof可以有一...

redis持久化RDB與AOF

redis是一種記憶體型資料庫,一旦伺服器程序退出,資料庫的資料就會丟失,為了解決這個問題,redis提供了兩種持久化的方案,將記憶體中的資料儲存到磁碟中,避免資料的丟失。redis提供了rdb持久化的功能,這個功能可以將redis在記憶體中的的狀態儲存到硬碟中,它可以手動執行。也可以再redis....