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相關學習資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章