Redis持久化——AOF日誌

最新:Redis記憶體——記憶體消耗(記憶體都去哪了?)

最新:Redis持久化——如何選擇合適的持久化方式

最新:Redis持久化——AOF日誌

更多文章…

上一篇文章Redis持久化——記憶體快照(RDB)我們總結到使用Redis記憶體快照進行持久化,在t 時刻做了一次快照,然後又在 t+n 時刻做了一次快照,此時如果宕機,則會丟失在此期間內修改的數據。但又不能頻繁的進行記憶體快照,那麼有什麼辦法能夠儘可能的減少這種數據丟失呢?Redis提供了另一種持久化的方式——AOF日誌(Append Only File)。

什麼是AOF日誌持久化

執行後寫日誌

與記憶體快照保存當前記憶體中的數據所不同,AOF持久化是通過保存Redis伺服器所執行的寫命令來記錄資料庫狀態的。即每執行一個命令,就會把該命令寫到日誌文件里。

需要注意的是寫日誌的操作在Redis執行命令將數據寫入記憶體之後,如下圖所示:

AOF-1

這樣做的好處就是不會阻塞當前操作,也可以避免額外的檢查開銷,如果是在命令執行前進行寫日誌的操作,一旦命令語法是錯誤的,不進行檢查的話就會導致寫入到日誌文件中的命令是錯誤的,在使用日誌文件恢複數據的時候就會出錯。而在命令執行後在進行日誌的寫入則不會有這個問題。

但是也存在兩個問題,

  1. AOF 雖然避免了對當前命令的阻塞,但卻可能會給下一個操作帶來阻塞風險。因為,AOF 日誌是在主進程中執行的,如果在把日誌文件寫入磁碟時,磁碟寫壓力大,就會導致寫盤很慢,進而導致後續的操作也無法執行了

  2. 如果剛執行完一個命令,還沒有來得及記日誌就宕機了,那麼這個命令和相應的數據就有丟失的風險。如果此時 Redis 是用作快取,還可以從後端資料庫重新讀入數據進行恢復,但是,如果 Redis 是直接用作資料庫的話,此時,因為命令沒有記入日誌,所以就無法用日誌進行恢復了。

AOF 緩衝區

針對上面兩個問題,Redis提供了緩衝區的方式進行AOF日誌的記錄,以達到儘可能的避免阻塞和數據丟失的問題。

Redis在執行完命令進行持久化的時候,並非直接寫入磁碟日誌文件,而是先寫入AOF緩衝區內,之後再通過某種策略寫到磁碟。

AOF-2

使用快取區的方式進行AOF日誌的記錄,上面提到的兩個問題其實就和日誌從緩衝區寫入磁碟的時機有關係。

三種回寫策略

Redis AOF 機制提供了三種回寫磁碟的策略。

  • Always(同步寫回): 命令寫入 AOF緩衝區後調用系統 fsync操作同步到AOF文件, fsync完成後執行緒返回
  • Everysec(每秒寫回): 命令寫人 AOF緩衝區後調用系統 write操作, write完成後執行緒返回。 fsync同步文件操作由專門執行緒每秒調用一次
  • No(作業系統自動寫回): 命令寫入 AOF緩衝區後調用系統 write操作,不對AOF文件做 fsync同步,同步硬碟操作由作業系統負責,通常同步周期最長30秒

但其實可以看出這三種回寫策略都並不能完美的解決問題,

配置為 always時,每次寫入都要同步AOF文件,硬碟的寫入速度無法與記憶體相提並論,顯然與 Redis髙性能特性背道而馳

配置為no,由於作業系統每次同步AOF文件的周期不可控,而且會加大每次同步硬碟的數據量,雖然提升了性能,但數據安全性無法保證。

配置為 everysec,是建議的同步策略,也是默認配置,雖然能做到兼顧性能和數據安全性。但極端情況下一會造成1秒內的數據丟失。

在真正使用中,我們可以根據具體對性能和數據完整性的要求,分析這三種回寫策略,選擇適合的策略來進行持久化。

回寫策略 優點 缺點
Always(同步寫回) 可靠性高、數據基本不丟失 性能較差
Everysec(每秒寫回) 性能適中 宕機時丟失1秒內的數據
No(作業系統自動寫回) 性能好 宕機時丟失數據較多

AOF重寫

日誌文件越來越大怎麼辦

選擇了合適的回寫策略,AOF這種持久化的方式還有其它問題嗎?

因為AOF持久化是通過保存被執行的寫命令來記錄資料庫狀態的,所以隨著時間的流逝,AOF文件中的內容會越來越多,文件的體積也會越來越大,過大的AOF文件不僅追加命令會變慢,而且可能對Redis伺服器、甚至整個宿主電腦造成影響,並且AOF文件的體積越大,使用AOF文件來進行數據還原所需的時間就越多。

這個時候就要用到AOF重寫機制了

redis> set testKey testValue
OK
redis> set testKey testValue1
OK
redis> del testKey
OK
redis> set testKey hello
OK
redis> set testKey world
OK

AOF 文件是以追加的方式,逐一記錄接收到的寫命令的。當一個鍵值對被多條寫命令反覆修改時,AOF 文件會記錄相應的多條命令。如上示例,我們執行完命令後,Redis會在AOF裡面追加5條命令。但實際上只需要set testKey world一條命令就夠了。

AOF 重寫機制就是在重寫時,Redis 根據資料庫的現狀創建一個新的 AOF 文件,也就是說,讀取資料庫中的所有鍵值對,然後對每一個鍵值對用一條命令記錄它的寫入。比如說,當讀取了鍵值對「testkey」: 「world」之後,重寫機制會記錄 set testkey world這條命令。這樣,當需要恢復時,可以重新執行該命令,實現「testkey」: 「world」的寫入。

這樣,重寫後的日誌,從5條變成了1條,而對於可能被修改過成百上千次的鍵值對來說,重寫能節省的空間就更大了。

雖然 AOF 重寫後,日誌文件會縮小,但是,要把整個資料庫的最新數據的操作日誌都寫回磁碟,仍然是一個非常耗時的過程。這時,我們不得不關註:重寫會不會導致阻塞?這就要看看AOF重寫的過程是怎麼樣的

AOF 重寫過程

因為AOF重寫也是一個非常耗時的過程,又因為Redis單執行緒的特性,同記憶體快照一樣,AOF重寫的過程也是由父進程fork出bgrewriteaof子進程來完成的.

使用子進程(而不是開啟一個執行緒)進行AOF重寫雖然可以避免使用鎖的情況下,保證數據安全性,但是會帶來子進程和父進程一致性問題。
例如在開始重寫之後父進程又接收了新的鍵值對此時子進程是無法知曉的,當子進程重寫完成後的資料庫和父進程的資料庫狀態是不一致的。

如下表:

時間 伺服器進程(父進程) 子進程
T1 執行命令 SET K1 V1
T2 執行命令 SET K1 V1
T3 創建子進程,執行AOF文件重寫 開始AOF重寫
T4 執行命令 SET K2 V2 執行重寫
T5 執行命令 SET K3 V3 執行重寫
T6 執行命令 SET K4 V4 完成AOF重寫

在T6時刻伺服器進程有了4個鍵,而子進程卻只有1個鍵

為了解決這種不一致性,Redis設置了一個AOF重寫緩衝區。

AOF重寫

在子進程執行AOF重寫期間。伺服器進程需要執行以下3個動作:

  1. 執行客戶端命令
  2. 執行後追加到AOF緩衝區
  3. 執行後追加到AOF重寫緩衝區

子進程完成AOF重寫後,它向父進程發送一個訊號,父進程收到訊號後會調用一個訊號處理函數,該函數把AOF重寫緩衝區的命令追加到新AOF文件中然後替換掉現有AOF文件。父進程處理完畢後可以繼續接受客戶端命令調用,可以看出在AOF後台重寫過程中只有這個訊號處理函數會阻塞伺服器進程。
下表是完整的AOF後台重寫過程:

時間 伺服器進程(父進程) 子進程
T1 執行命令 SET K1 V1
T2 執行命令 SET K1 V1
T3 創建子進程,執行AOF文件重寫 開始AOF重寫
T4 執行命令 SET K2 V2 執行重寫
T5 執行命令 SET K3 V3 執行重寫
T6 執行命令 SET K4 V4 完成AOF重寫,向父進程發送訊號
T7 接收到訊號,將T5 T6 T7 伺服器的寫命令追加到新的AOF文件末尾
T8 用新的AOF替換舊的AOF

這樣就可以保證重寫日誌期間的所有操作也都會寫入新的AOF文件。

需要注意的是, T7 T8執行的任務會阻塞伺服器處理命令。

總的來說,就是每次 AOF 重寫時,Redis 會先fork出一個子進程用於重寫;然後,使用兩個日誌保證在重寫過程中,新寫入的數據不會丟失。

AOF文件恢復

Redis 伺服器重啟後,會優先去載入AOF日誌文件。因為AOF文件裡面包含了重建資料庫狀態所需的所有寫命令,所以伺服器重新執行一遍AOF文件裡面保存的寫命令,就可以還原伺服器關閉之前的資料庫狀態。

而由於Redis命令只能在客戶端上下文中執行,Redis會創建一個沒有網路連接的偽客戶端來執行AOF文件中的內容。

小結

本文主要總結了Redis AOF 持久化的方式,介紹了它同步磁碟的三種策略,以及日誌文件過大時如何進行重寫。我們知道Redis持久化方式有AOF和RDB兩種,那麼這兩種持久化方式各自有什麼優點和缺點?真正使用中我們應該如何去選擇合適的持久化方式,又可能遇到哪些問題呢?我們下一篇文章繼續總結

系列文章:

最新:Redis記憶體——記憶體消耗(記憶體都去哪了?)

最新:Redis持久化——如何選擇合適的持久化方式

最新:Redis持久化——AOF日誌

Redis持久化——記憶體快照(RDB)

一文回顧Redis五大對象(數據類型)

Redis對象——有序集合(ZSet)

Redis對象——集合(Set)

Redis對象——列表(List)

Redis對象——哈希(Hash)

Redis數據結構——quicklist

Redis對象——字元串

Redis對象——Redis對象系統簡介

Redis數據結構——壓縮列表

Redis數據結構——整數集合

Redis數據結構——跳躍表

Redis數據結構——字典

Redis數據結構——鏈表

Redis數據結構——簡單動態字元串SDS

—–END—–

關注下方公眾號,回復「Redis」,可得Redis相關學習資料

Tags: