1. 程式人生 > >redis 系列17 持久化 AOF

redis 系列17 持久化 AOF

一.概述

  除了上篇介紹的RDB持久化功能之外,Redis還提供了AOF(Append Only File)持久化功能。與RDB儲存資料庫中的鍵值對來記錄資料庫狀態不同,AOF是通過儲存redis伺服器所執行的寫命令來記錄資料庫狀態的。AOF持久化方式記錄每次對伺服器寫的操作,當伺服器啟動時,就會通過載入和執行AOF檔案中儲存的命令來還原伺服器關閉之前的資料庫狀態,並在伺服器載入AOF檔案並還原資料庫狀態時列印日誌。

  被寫入AOF檔案的所有命令都是純文字格式,可以直接開啟一個AOF檔案來觀察。所有寫命令是以追加(append)形式,儲存到檔案末尾。Redis還能對AOF檔案進行後臺重寫,使得AOF檔案的體積不至於過大。

  1.1 AOF持久化的實現

    AOF持久化功能的實現可以分為命令追加(append),檔案寫入,檔案同步(sync)三個步驟。

    (1) 命令追加

      當AOF執行處於開啟狀態時,伺服器在執行完一個寫命令之後,會以協議格式將被執行的寫命令追加到伺服器狀態的AOF_buf緩衝區的末尾。

    struct redisServer { 
             //..
             //aof 緩衝區
              ads aof_buf
             //..
        }

    (2) AOF檔案寫入與同步

      Redis的伺服器程序就是一個事件迴圈(loop),這個迴圈中的檔案事件負責接收客戶端的命令請求,以及向客戶端傳送命令回覆。在伺服器每次結束一個事件迴圈之前,都會呼叫內部flushAppendOnlyFile函式,考慮是否需要將aof_buf緩衝區中的內容寫入和儲存到AOF檔案裡面。flushAppendOnlyFile函式的行為由伺服器配置appendfsync選項的值來決定。appendfsync是指資料同步到磁碟檔案(AOF)的方式,預設配置是everysec選項。當同步頻率是everysec值時,並且距離上次同步AOF檔案已經超過一秒時,那麼伺服器會先將aof_buf中的內容寫入到AOF檔案中。  

    127.0.0.1:6379>config get Appendfsync
    1) "appendfsync"
    2) "everysec"

Appendfsync模式

對應flushAppendOnlyFile函式行為

no

當設定appendfsync為no的時候,Redis不會主動呼叫fsync去將AOF日誌內容同步到磁碟,所以這一切就完全依賴於作業系統的除錯了。對大多數Linux作業系統,是每30秒進行一次fsync,將緩衝區中的資料寫到磁碟上。從效率上講該模式最快,

但同步到磁碟不及時,是最不安全的選擇。

Everysec (推薦)

當設定appendfsync為everysec的時候,Redis會預設每隔一秒進行一次fsync呼叫,將緩衝區中的資料寫到磁碟,從效率上講該模式足夠快(和使用 RDB 持久化差不多),並且當出現故障停機時,資料庫也只丟失一秒鐘的命令。

always

當設定appendfsync為always時,每一次寫操作都會呼叫一次fsync,這時資料是最安全的,當然,由於每次都會執行fsync,所以其效能也會受到影響,效率上講該模式最慢的。

    

  1.2 AOF檔案載入與資料還原

    因為AOF檔案裡面包含了重建資料庫狀態所需的所有寫命令,所以伺服器只要讀入並重新執行一遍AOF檔案裡面儲存的寫命令,就可以還原伺服器關閉之前的資料庫狀態。Redis讀取AOF檔案並還原資料庫狀態的詳細步驟如下:

    (1) 建立一個偽客戶端(因為Redis的命令只能在客戶端上下文中執行),用於載入AOF檔案時所使用的命令直接來源於AOF檔案,而不是來自網路連線的命令。

    (2) 從AOF檔案中分析並讀出一條寫命令。

    (3) 使用偽客戶端執行被讀出的寫命令。

    (4) 重複執行步驟2和3,直到AOF檔案中的所有命令都被處理完為止。

    比如:伺服器首先讀入並執行select 0 命令,之後是set msg hello命令,再之後是sadd fruits apple banana cherry命令等等,這些命令都執行完之後,伺服器的資料庫就被還原到之前的狀態了。

  

  1.3 AOF重寫

    因為AOF持久化是通過儲存被執行的寫命令來記錄資料庫狀態的,所以隨著伺服器執行時間的流逝,AOF檔案中的內容會越來越多,檔案 的體積也會越來越大,隨著AOF檔案的體積越大,資料還原所需的時間就越多。為了解決AOF檔案體積膨脹的問題,Redis提供了AOF檔案重寫功能。通過該功能,Redis伺服器可以建立一個新的AOF檔案來替代現有的AOF檔案,新舊兩個AOF檔案所儲存的資料庫狀態相同,但新的AOF檔案不會包含任何浪費空間的冗餘命令,所以新AOF檔案體積比舊的AOF檔案體積要小得多。

    AOF檔案重寫並不需要對現有的AOF檔案進行任何讀取,分析或者寫入操作,這個重寫功能是通過讀取伺服器當前的資料庫狀態來實現的。比如:使用寫命令 rpush list "A", rpush list "B", rpush list "C", rpush list "D" 此時必須在AOF檔案中寫入四條命令。重寫可以是直接從資料庫中讀取鍵list的值,然後用一條rpush list "A","B","C","D"命令來代替。

  

  1.4  AOF 後臺重寫

    重寫作為一種輔助維護,Redis不希望AOF重寫造成伺服器無法處理請求,所以Redis決定將AOF重寫程式放到子程序裡執行。對AOF 檔案進行重寫,執行bgrewriteaof命令, Redis將生成一個新的 AOF 檔案,這個檔案包含重寫當前資料集所需的最少命令。bgrewriteaof後臺重寫實現步驟如下:

    (1) Redis執行 fork() ,現在同時擁有父程序和子程序。

    (2)子程序開始將新 AOF 檔案的內容寫入到臨時檔案。

    (3)對於所有新執行的寫入命令,父程序一邊將它們累積到一個記憶體快取中,一邊將這些改動追加到現有 AOF 檔案的末尾,這樣樣即使在重寫的中途發生停機,現有的 AOF 檔案也還是安全的。

    (4)當子程序完成重寫工作時,它給父程序傳送一個訊號,父程序在接收到訊號之後,將記憶體快取中的所有資料追加到新 AOF 檔案的末尾。

    (5)現在Redis原子地用新檔案替換舊檔案,之後所有命令都會直接追加到新 AOF 檔案的末尾。

  

  1.5 AOF優點

    (1) 可以使用不同的fsync(同步)策略:無fsync、每秒fsync、每次寫的時候fsync。使用預設的每秒fsync策略,Redis的效能依然很好(fsync是由後臺執行緒進行處理的,主執行緒會盡力處理客戶端請求),一旦出現故障,你最多丟失1秒的資料。

    (2) AOF檔案是一個只進行追加的日誌檔案,所以不需要寫入seek,某些原因(如:宕機)未執行完整的寫入命令,你也可使用redis-check-aof工具修復這些問題。

    (3) AOF 檔案體積變得過大時,自動地在後臺對 AOF 進行重寫.整個重寫操作是絕對安全,即使重寫過程中發生停機,現有的 AOF 檔案也不會丟失。一旦新 AOF 檔案建立完畢,Redis就會從舊 AOF 檔案切換到新 AOF 檔案,並開始對新 AOF 檔案進行追加操作。

    (4) AOF 檔案有序地儲存了對資料庫執行的所有寫入操作,這些寫入操作以Redis協議的格式儲存,因此 AOF 檔案的內容非常容易被人讀懂,對檔案進行分析(parse)也很輕鬆。匯出(export) AOF 檔案也非常簡單。舉個例子:如果你不小心執行了 FLUSHALL 命令,但只要 AOF 檔案未被重寫,那麼只要停止伺服器,移除 AOF 檔案末尾的 FLUSHALL 命令,並重啟Redis,就可以將資料集恢復到 FLUSHALL 執行之前的狀態。

  

  1.5  AOF缺點

    (1) 對於相同的資料集來說,AOF 檔案的體積通常要大於 RDB 檔案的體積。

    (2) 根據所使用的fsync(同步)策略,AOF 的速度可能會慢於 RDB 。在一般情況下,每秒fsync的效能依然非常高,而關閉fsync可以讓 AOF 的速度和 RDB 一樣快,即使在高負荷之下也是如此。不過在處理巨大的寫入載入時,RDB 可以提供更有保證的最大延遲時間(latency)。

  

  1.6 如何選擇使用哪種持久化方式

     一般來說,如果想達到足以媲美PostgreSQL的資料安全性,應該同時使用兩種持久化功能。如果你非常關心你的資料,但仍然可以承受數分鐘以內的資料丟失,那麼你可以只使用 RDB 持久化。

    有很多使用者都只使用 AOF 持久化,但我們並不推薦這種方式:因為定時生成 RDB 快照(snapshot)非常便於進行資料庫備份,並且 RDB 恢復資料集的速度也要比 AOF 恢復的速度要快,除此之外,使用 RDB 還可以避免之前提到的 AOF 程式的 bug 。注意: 因為以上提到的種種原因,未來可能會將 AOF 和 RDB 整合成單個持久化模型。

   

二.  AOF持久化配置

  redis預設是關閉AOF機制,需要在配置檔案中開啟AOF, 注意通過 CONFIG SET 設定的配置重啟Redis服務後就會失效,如果要永久有效,需在redis.conf中開啟AOF功能。指令碼如下:

    127.0.0.1:6379>config set appendonly yes
    OK

  開啟後每當Redis執行一個改變資料集的命令時(如:set),這個命令就會被追加到AOF檔案的末尾,這樣當redis重新啟動時,程式就可以通過重新執行AOF檔案中的命令來達到重建資料集的目的。

  

  2.1 AOF配置相關選項

選項

取值

說明

Appendonly

no|yes

是否開啟AOF機制

Appendfilename

"appendonly.aof"

Aof檔名

Appendfsync

no|appendfsync|always

AOF持久化同步頻率

no-appendfsync-on-rewrite

No | yes

在日誌進行BGREWRITEAOF時,如果設定為yes表示新寫操作不進行同步fsync,只是暫存在緩衝區裡,避免造成磁碟IO操作衝突,等重寫完成後在寫入。redis中預設為no 

 

auto-aof-rewrite-percentage

100

當前AOF檔案大小是上次日誌重寫時的AOF檔案大小兩倍時,發生BGREWRITEAOF操作。

auto-aof-rewrite-min-size

64mb

當前AOF檔案執行BGREWRITEAOF命令的最小值,避免剛開始啟動Reids時由於檔案尺寸較小導致頻繁的BGREWRITEAOF。

aof-load-truncated

yes

Redis再恢復時,忽略最後一條可能存在問題的指令

aof-use-rdb-preamble

no

新增RDB-AOF混合持久化格式,在開啟了這個功能之後,AOF重寫產生的檔案將同時包含RDB格式的內容和AOF格式的內容

  2.2 演示

    下面測試AOF持久化,AOF檔案是可識別的純文字,檔案的內容就是一個個的Redis標準命令,下面使用兩個set命令:

    127.0.0.1:6379> set name1 "zs"
    OK
    127.0.0.1:6379> set name2 "ls"
    OK

    下面檢視AOF檔案, 可以發現裡面是一個個命令, 上面執行的寫命令對應的檔案內容如下:

    [[email protected] redis]$ cat appendonly.aof
    name1
    $2
    zs
    *3
    $3
    set
    $5
    name2
    $2
    ls