Redis-技術專區-幫從底層徹底吃透AOF技術原理

李浩宇Alex發表於2021-09-04

AOF持久化方式

AOF持久化方式是將redis的操作日誌以追加的方式寫入磁碟檔案中。AOF持久化是以日誌的形式記錄伺服器所處理的每一個寫、刪除操作,查詢操作不會記錄,以文字的方式記錄,可以開啟檔案看到詳細的操作記錄。

AOF實現方式

  • AOF(append only file)持久化是以獨立日誌的方式記錄每次寫命令,重啟時再重新執行AOF檔案中命令達到恢復資料的目的。
  • AOF的主要作用是解決了資料持久化的實時性,目前已經是Redis持久化的主流方式。

AOF優勢

  • 該機制可以帶來更高的資料安全性,即資料永續性。

  • Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步

    • 每秒同步:事實上,每秒同步也是非同步完成的,其效率也是非常高的,所差的是一旦系統出現當機現象,那麼這一秒鐘之內修改的資料將會丟失。

    • 每次修改:而每修改同步,我們可以將其視為同步持久化,即每次發生的資料變化都會被立即記錄到磁碟中。

    • 不同步:可以預見,這種方式在效率上是最低的。至於無同步,無需多言,我想大家都能正確的理解它。

  • 由於該機制對日誌檔案的寫入操作採用的是append模式,因此在寫入過程中即使出現當機現象,也不會破壞日誌檔案中已經存在的內容

  • 如果我們本次操作只是寫入了一半資料就出現了系統崩潰問題,不用擔心,在Redis下一次啟動之前,我們可以通過redis-check-aof工具來幫助我們解決資料一致性的問題。

  • 如果日誌過大,Redis可以自動啟用rewrite機制,壓縮和瘦身相關的aof檔案。

    • Redis以append模式不斷的將修改資料寫入到老的磁碟檔案中,同時Redis還會建立一個臨時的新檔案用於記錄此期間有哪些修改命令被執行。

    • 因此在進行rewrite切換時可以更好的保證資料安全性。

AOF包含一個格式清晰、易於理解的日誌檔案用於記錄所有的修改操作。事實上,我們也可以通過該檔案完成資料的重建。


AOF命令寫入

AOF命令寫入的內容直接是文字協議格式。AOF檔案是純文字檔案,其內容正是Redis客戶端向Redis傳送的原始通訊協議的內容。

例如:set hello world 這條命令,在AOF緩衝區會追加如下文字:

$3
set
$5
hello
$5
world
  • $3 : set指令的長度。set長度 == 3
  • set:代表著set指令
  • $5:hello key對應的值長度
  • hello:key值
  • $5:world value對應的值長度
  • world:value值

  1. AOF為什麼直接採用文字協議格式?可能的理由如下:

    • 文字協議具有很好的相容性。
       - 開啟AOF後,所有寫入命令都包含追加操作,直接採用協議格式,避免二次處理開銷。
    • 文字協議具有可讀性,方便直接修改和處理。
  2. AOF為什麼把命令追加到aof_buf中?

    • Redis使用單執行緒響應命令,如果每次寫AOF檔案命令都直接追加到硬碟,那麼效能完全取決於當前硬碟負載。
    • 先寫入緩衝區aof_buf中,還有另一個好處,Redis可以提供多種緩衝區同步硬碟的策略,在效能和安全性方面做出平衡。

AOF配置

在redis的redis.conf配置檔案中:

開啟檔案,找到 APPEND ONLY MODE 對應內容,預設情況下Redis沒有開啟AOF(append only file)方式的持久化,通過appendonly引數開啟

  1. AOF檔案的儲存位置和RDB檔案的位置相同
都是通過dir引數設定的
dir /path
  1. redis 預設關閉,開啟需要手動把no改為yes
appendonly yes 
  1. 指定本地資料庫檔名,預設值為 appendonly.aof
appendfilename "appendonly.aof"

  1. Redis支援三種不同的刷寫模式,Redis提供了多種AOF緩衝區同步檔案策略,由引數appendfsync控制:

    • 每次有資料修改發生時都寫入AOF檔案中

      • 每次收到寫命令就立即強制寫入磁碟,是最有保證的完全的持久化,但速度也是最慢的,一般不推薦使用
      appendfsync always
      
      • 在一般的STAT硬碟上,Redis只能支援大約幾百TPS寫入,這是最安全也是最慢的方式,顯然跟Redis高效能特性背道而馳,不建議配置。
    • 每秒中同步一次,將過去一秒內發生的資料修改寫入AOF檔案中

      • 每秒鐘強制寫入磁碟一次,在效能和持久化方面做了很好的折中,是受推薦的方式。
      appendfsync everysec
      
      • 是建議的同步策略,也是預設配置,做到兼顧效能和資料安全性,理論上只有在系統突然當機的情況下丟失1s的資料。(嚴格來說最多丟失1s資料是不準確)
    • 不主動同步,高效但是資料不持久化,由作業系統來決定

      • 完全依賴OS的寫入,一般為30秒左右一次,效能最好但是持久化最沒有保證,不被推薦。
      appendfsync no
      
      • 由於作業系統每次同步AOF檔案的週期,(即每30秒一次),而且會極大每次同步硬碟的資料量,雖然提升了效能,但資料安全性無法保證。

  1. Redis服務的AOF檔案同步策略:

    • always (最安全但是最慢) :同步持久化,每次發生資料變化會立刻寫入到磁碟中。效能較差當資料完整性比較好(慢,安全)
    • everysec (預設的同步策略):出廠預設推薦,每秒非同步記錄一次(預設值)
    • no (最快但是不安全):不同步
  2. 當程式中BGSAVE或BGREWRITEAOF命令正在執行時不阻止主程式中的fsync()呼叫(預設為no,當存在延遲問題時需調整為yes).

no-appendfsync-on-rewrite no

雖然每次執行更改資料庫內容的操作時,AOF都會將命令記錄在AOF檔案中,但是事實上,由於作業系統的快取機制,資料並沒有真正地寫入硬碟,而是進入了系統的硬碟快取。在預設情況下系統每30秒會執行一次同步操作,以便將硬碟快取中的內容真正地 寫入硬碟,在這30秒的過程中如果系統異常退出則會導致硬碟快取中的資料丟失。一般來講啟用AOF持久化的應用都無法容忍這樣的損失,這就需要Redis在寫入AOF檔案後主動要求系統將快取內容同步到硬碟中。

AOF重寫機制

隨著命令不斷寫入AOF,檔案會越來越大,為了解決這個問題,Redis引入了AOF重寫機制壓縮檔案體積。AOF檔案重寫是把Redis程式內的資料轉化為寫命令同步到新AOF檔案的過程。

AOF重寫原理

重寫後的AOF檔案為什麼可以變小?有如下原因:

  1. 程式內已經超時的資料不再寫檔案。
  2. 舊的AOF檔案含有無效命令,如del key1、set a 111、set a 222等。重寫使用程式內資料直接生成,這樣新的AOF檔案只保留最終資料的寫入命令。
  3. 多條寫命令可以合併為一個,如lpush list a、lpush list b、 lpush list c 可以轉化為:lpush list a b c。

為了防止合併的資料過大造成客戶端緩衝區溢位,對於list、set、hash、zset等型別,以64個元素為界拆分為多條。

AOF重寫原理

AOF的工作原理是將寫操作追加到檔案中,檔案的冗餘內容會越來越多。所以聰明的 Redis 新增了重寫機制。當AOF檔案的大小超過所設定的閾值時,Redis就會對AOF檔案的內容壓縮。

Redis 會fork出一條新程式,讀取記憶體中的資料,並重新寫到一個臨時檔案中。並沒有讀取舊檔案。最後替換舊的aof檔案。

需要壓縮重寫的案例:
  • AOF帶來了另一個問題,持久化檔案會變得越來越大。比如,我們呼叫INCR test命令100次,檔案中就必須儲存全部的100條命令,但其實99條都是多餘的。

    • 因為要恢復資料庫的狀態其實檔案中儲存一條SET test 100就夠了。
  • 為了合併重寫AOF的持久化檔案,Redis提供了bgrewriteaof命令。收到此命令後,Redis將使用與快照類似的方式將記憶體中的資料以命令的方式儲存到臨時檔案中,最後替換原來的檔案,以此來實現控制AOF檔案的合併重寫(會將重寫過程中接收的的新的指令和生成新的重寫後AOF檔案中的指令進行合併)。

注意:由於是模擬快照的過程,因此在重寫AOF檔案時並沒有讀取舊的AOF檔案,而是將整個記憶體中的資料庫內容用命令的方式重寫了一個新的AOF檔案

AOF重寫目的
  • AOF重寫降低了檔案佔用空間,除此之外,另一個目的是:更小的AOF檔案可以更快地被Redis載入。
AOF重寫過程可以手動觸發和自動觸發:
  • 配置重寫rewrite觸發機制
    • 手動觸發:直接呼叫bgrewriteaof命令
    • 自動觸發:根據auto-aof-rewrite-min-size和auto-aof-rewrite-percentage引數確定自動觸發時機
      • auto-aof-rewrite-min-size: 限制了允許重寫的最小AOF檔案,通常在AOF檔案很小的時候即使其中有些冗餘命令也可是可以忽略的。
      • auto-aof-rewrite-percentage: 當前的AOF檔案大小超過上一次重寫的AOF檔案大小的百分之多少時會再次進行重寫,如果之前沒有重寫過,則以啟動時的AOF大小為依據。

注意,執行AOF重寫請求時,父程式依然響應命令,Redis使用"AOF重寫緩衝區"儲存這部分新資料,防止新AOF檔案生成期間丟失這部分資料。

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

解釋含義:當AOF檔案大小是上次rewrite後大小的一倍且檔案大於64M時觸發。一般都設定為3G,64M太小了, 這裡的“一倍”和“64M” 可以通過配置檔案修改。


AOF與RDB二者選擇的標準(結合上一篇文章)

權衡的標準是對資料的一致性要求和效能之間的平衡。看系統是願意犧牲一些效能,換取更高的快取一致性(AOF),還是願意寫操作頻繁的時候,不啟用備份來換取更高的效能,待手動執行save的時候,再做備份(RDB)。

AOF的執行流程

開啟AOF持久化後每執行一條會更改Redis中的資料的命令,Redis就會將該命令寫入硬碟中的AOF檔案。

AOF的工作流程操作有:

  • 命令寫入(append)
  • 檔案同步(sync)
  • 檔案重寫(rewrite)
  • 重啟載入(load)

AOF流程如下:

  1. 所有的寫入命令會追加到aof_buf(緩衝區)中。
  2. AOF緩衝區根據對應的策略向硬碟做同步操作。
  3. 隨著AOF檔案越來越大,需要定期對AOF檔案進行重寫,達到壓縮的目的。
  4. 當Redis服務重啟時,可以載入AOF檔案進行資料恢復。

AOF重啟載入

  • AOF和RDB檔案都可以用於伺服器重啟時的資料恢復。

    1. AOF持久化開啟且存在AOF檔案時,優先載入AOF檔案;

    2. AOF關閉或者AOF檔案不存在時,載入RDB檔案;

    3. 載入AOF/RDB檔案城後,Redis啟動成功;

    4. AOF/RDB檔案存在錯誤時,Redis啟動失敗並列印錯誤資訊。

根據AOF檔案恢復資料

正常情況下,將appendonly.aof 檔案拷貝到redis的安裝目錄的bin目錄下,重啟redis服務即可。但在實際開發中,可能因為某些原因導致appendonly.aof 檔案格式異常,從而導致資料還原失敗,可以通過命令redis-check-aof --fix appendonly.aof 進行修復 。從下面的操作演示中體會。

若打算使用Redis 的持久化。建議RDB和AOF都開啟。其實RDB更適合做資料的備份,
留一後手。AOF出問題了,還有RDB。

AOF 的優缺點

AOF 優點

資料的完整性和一致性更高

AOF劣勢

  • 相同數量的資料集而言,AOF檔案通常要大於RDB檔案。RDB在恢復大資料集時的速度比 AOF 的恢復速度要快。

  • 同步策略的不同,AOF在執行效率上往往會慢於RDB。總之,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB一樣高效。

  • 資料的完整性和一致性更高因為AOF記錄的內容多,檔案會越來越大,資料恢復也會越來越慢。

  • 對於相同數量的資料集而言,AOF檔案通常要大於RDB檔案。RDB 在恢復大資料集時的速度比 AOF 的恢復速度要快。

總結

每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB一樣高效。

  • AOF 的資料完整性比RDB高,但記錄內容多了,會影響資料恢復的效率。
  • RDB與AOF二者選擇的標準,就是看系統是願意犧牲一些效能,換取更高的快取一致性(aof),還是願意寫操作頻繁的時候,不啟用備份來換取更高的效能,待手動執行save的時候,再做備份(rdb)。
  • Redis允許同時開啟AOF和RDB,既保證了資料安全又使得進行備份等操作十分容易。此時重新啟動Redis後Redis會使用AOF檔案來恢復資料,因為AOF方式的持久化可能丟失的資料更少。
  • 若只打算用Redis 做快取,可以關閉持久化。

相關文章