Redis:持久化之AOF

《Redis:持久化之RDB》的最後,我們說到RDB持久化存在一個問題那就是一旦Redis發送異常退出,就會丟失最後一次快照以後更改的所有數據,這可能是幾秒或者更長的一個時間丟失。我們也說到如果無法忍受近幾秒或者更長的數據丟失,則可以考慮使用AOF方式進行持久化。那麼AOF方式又是怎樣的呢?往下看。

1. AOF簡介

RDB是通過保存數據庫中鍵值對的數據來達到持久化的目的,而AOF則是通過保存Redis服務器所執行的寫命令來記錄數據庫狀態。比如以下命令:

在這裏插入圖片描述

RDB持久化方式則是將aof-test-key1aof-test-key2兩個鍵值對保存在RDB的快照文件中,而對於AOF持久化方式則是將兩條set命令保存在AOF文件中。

2. 開啓AOF

默認情況下Redis不開啓AOF方式的持久化,但我們可以通過appendonly參數啓用:

appendonly yes

開啓AOF持久化後每執行一條修改數據的命令,Redis就會將該命令寫入磁盤的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通過dir參數進行設置。默認情況下,AOF持久化生成的文件名爲appendonly.aof,我們也可以通過appendfilename參數修改:

appendfilename appendonly.aof

3. 數據恢復

接下來演示一下,Redis基於AOF方式恢復數據的過程。

場景一:驗證AOF持久化已經在起作用了。

(1)我們先刪除dump.rdbappendonly.aof文件,然後寫入k1,然後通過kill命令殺死進程。

在這裏插入圖片描述

(2)可以看到重新生成了appendonly.aof文件,此時我們重啓redis服務,看k1的值是否被持久化。(可以看到k1的值被持久化,而該值就是從AOF文件恢復回來的。)

在這裏插入圖片描述

場景二:驗證redis啓動時,是從AOF文件恢復持久化數據,而非dump.rdb。

(1)我們在設置一個k2的值,然後通過redis-cli shutdown停掉redis進程。

在這裏插入圖片描述

(2)重啓redis服務,此時dump.rdb和appendonly.aof都記錄了k2的值,無法看出redis重啓是否是從aof中恢復的。那麼我們再寫入k3,然後通過kill -9殺死redis進程。(我們知道用kill方式殺死進程,持久化數據是不會被寫進dump.rdb中的)

在這裏插入圖片描述

(3)重啓redis服務,看下k3是否被持久化,若被持久化,則可驗證redis啓動時,從aof文件中恢復數據。

在這裏插入圖片描述

4. AOF重寫

先看下面一組命令:

在這裏插入圖片描述

正常來說,Redis的AOF持久化文件會記錄這三條命令,然而我們知道k1鍵值對最終的結果是3,也就是說前兩條命令其實是冗餘的,因爲這兩條的執行結果會被第三條命令覆蓋。隨着執行的命令越來越多,AOF文件的大小也會越來越大,即使內存中實際的數據可能並沒有多少。AOF文件越大的另外一個問題就是在Redis進行數據修復的時間也會越長。

很自然地,Redis提供了AOF文件的優化機制,就上面的一組命令而言,Redis在達到一定條件時會自動將前兩條無用的記錄刪除,只保留第三條,這樣就能大大減小AOF文件的大小。

4.1 重寫的條件

和重寫相關的條件配置如下:

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
  • auto-aof-rewrite-percentage:當目前AOF文件大小超過上一次重寫時AOF文件大小的百分之多少時再次進行重寫,如果之前沒有重寫過,則以啓動時的AOF文件大小爲依據。
  • auto-aof-rewrite-min-size:設置允許重寫的最小AOF文件大小,通常情況下當AOF文件很小的時候,即使有很多冗餘的命令我們也不需要關心。

當然除了讓Redis自動執行重寫外,我們也可以通過bgrewirteaof命令手動執行AOF重寫。

4.2 重寫的原理

我們知道Redis是單線程的,如果重寫AOF需要比較長的時間,那麼在重寫AOF的時候,Redis將長時間無法處理其它的命令,這顯然是不合乎情理的。所以Redis在重寫的時候,是將重寫程序放到子進程進行,這樣:

(1)子進程進行 AOF 重寫期間,服務器進程(父進程)可以繼續處理其他命令。

(2)子進程帶有父進程的數據副本,使用子進程而不是線程,可以在避免使用鎖的情況下,保證數據的安全性。

使用子進程解決了上面的問題,但是新問題也產生了:因爲子進程在進行 AOF 重寫期間,服務器進程依然在處理其它命令,這新的命令有可能也對數據庫進行了修改操作,使得當前數據庫狀態和重寫後的 AOF 文件狀態不一致。

爲了解決這個數據狀態不一致的問題,Redis 服務器設置了一個 AOF 重寫緩衝區,這個緩衝區是在創建子進程後開始使用,當Redis服務器執行一個寫命令之後,就會將這個寫命令也發送到 AOF 重寫緩衝區。當子進程完成 AOF 重寫之後,就會給父進程發送一個信號,父進程接收此信號後,就會調用函數將 AOF 重寫緩衝區的內容都寫到新的 AOF 文件中。

5. 同步磁盤數據

雖然打開AOF持久化方式後,Redis會將寫命令記錄下來,但實際上,由於操作系統的緩存機制,數據並沒有真正地立即寫入磁盤,而是進入系統的磁盤緩存。在默認情況下,系統每30秒會執行一次同步操作,以便將磁盤緩存中的內容真正落盤,假設在這30秒的過程中系統異常退出則會導致磁盤緩存中的數據丟失。

一般來講啓動AOF持久化的應用都無法忍受這樣的損失,那麼就需要Redis在寫入AOF文件後主動要求系統將磁盤緩存中的內容同步到磁盤中。在Redis中,我們可以通過appendfsync參數設置同步的時機:

# appendfsync always
appendfsync everysec
# appendfsync no

默認情況下Redis採用everysec規則,即每秒執行一次同步操作。

  • always:表示每次執行寫入都會執行同步,這是最安全也是最慢的方式。
  • no:表示不主動進行同步操作,由操作系統每隔30秒做一次同步,這是最快但也是最不安全的方式。

Redis允許同時開啓AOF和RDB持久化,此時重新啓動Redis後Redis會使用AOF文件來恢復數據,因爲相對而言,AOF方式的持久化可能丟失的數據更少。

——End——
更多精彩分享,可掃碼關注微信公衆號哦。

在這裏插入圖片描述

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