一.概述 除了上篇介紹的RDB持久化功能之外,Redis還提供了AOF(Append Only File)持久化功能。與RDB保存資料庫中的鍵值對來記錄資料庫狀態不同,AOF是通過保存redis伺服器所執行的寫命令來記錄資料庫狀態的。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文件, 可以發現裡面是一個個命令, 上面執行的寫命令對應的文件內容如下:
[hsr@xuegod64 redis]$ cat appendonly.aof name1 $2 zs *3 $3 set $5 name2 $2 ls