★ Redis24篇集合
1 介紹
AOF(Append Only File)持久化:以獨立日誌的方式儲存了 Redis 伺服器的順序指令序列,並只記錄對記憶體進行修改的指令。
當Redis服務發生雪崩等故障時,可以重啟服務並重新執行AOF檔案中的指令達到恢復資料的目的。也就是說,透過重放(replay),來重新建立 Redis 當前例項的記憶體資料結構。這種模式有沒有很熟悉,可以聯想到MySQL主從同步時的relay log。
相對於咱們上一篇介紹的《RDB記憶體快照提供持久化能力》定點快照的做法,AOF的主要作用是解決了資料持久化的實時性,目前已經是Redis持久化的主流方式。
2 AOF實現日誌記錄
2.1 開啟AOF日誌記錄
1、 開啟AOF日誌記錄:在redis.conf檔案中,找到 APPEND ONLY MODE 設定
appendonly yes # 預設不開啟, 為 no
2、配置預設檔名:在redis.conf檔案中設定
appendfilename “appendonly.aof”
2.2 執行流程
流程如上圖所示,我們解析如下:
2.2.1 將所有的寫命令(set、hset)Append 到aof_buf緩衝區中
Redis 接收到 set keyName someValue
命令的時候,會先將資料寫到記憶體,Redis 會按照如下格式寫入 AOF 檔案。
*3
:表示當前指令分為三個部分,每個部分都是$ +
數字開頭,後面是3部分的具體內容:指令、鍵、值。- 數字:表示這部分的命令、鍵、值多佔用的位元組大小。比如
$3
表示這部分包含 3 個字元,也就是 set 的長度。
我們看看一個典型的aof檔案示例,為了清晰表示,下面的註釋都是手動加的:
[root@localhost bin]#vim appendonly.aof
# 執行 set key value
*3
$3 # 這邊代表set命令,長度為3
set
$9
user_name # 這邊代表keyName,長度為9
$5
brand # 這邊代表keyValue,長度為5
# 執行 mset key1 1 ,key2 2 ,key33 3
# aof日誌如下:
*7 # 本批命令需要往下讀7行非 $ 開始的命令
$4 #接著讀取4個位元組寬度,‘mset’長度為4,記為 $4
mset
$4 #接著讀取4個位元組寬度,‘key1’長度為4,記為 $4
key1
$1 #接著讀取1個位元組寬度,‘1’長度為1,記為 $1
1
$4
key2
$1
2
$5 #接著讀取的位元組寬度,‘$key33’長度為5,記為 $5
key33
$1
3
2.2.2 AOF緩衝區根據策略向硬碟做sync同步
AOF為什麼把命令append到aof_buf中,然後再進行同步?
這是因為Redis使用單程序響應命令(參考筆者這篇《深刻理解高效能Redis的本質》),如果每次寫AOF檔案命令都直接持久化到硬碟,那麼操作會是不是被間斷,且效能完全取決於硬碟I/O負載。這個跟 MySQL 就沒啥區別了。
先寫入緩衝區aof_buf中,Redis可以提供多種緩衝區同步硬碟的策略,在效能、安全、資料可靠性方面做出平衡。
同步策略需關注以下幾個配置:
1、 appendfsync 模式
appendfsync always # 接受寫命令後立即寫入磁碟,強持久化但執行慢,不推薦
appendfsync everysec # 每秒寫入磁碟一次, 效能和持久化方面做了折中, 推薦
appendfsync no # 依賴作業系統自身同步的配置和策略,效能較佳,但是沒法保證實時和完全持久化
2、no-appendfsync-on-rewrite
在 AOF 重寫期間是否禁用 fsync。這可以提高重寫效能,但可能會增加資料丟失的風險。
# 預設值:no
# 可選值:yes 或 no
no-appendfsync-on-rewrite yes
2.2.3 AOF檔案Rewrite實現壓縮
隨著AOF檔案越來越大,需要定期對AOF檔案進行重寫,達到壓縮減負的目的,避免AOF檔案過大導致效能和資料可靠性問題。
重寫後的AOF檔案變小的原因主要有以下幾點:
1、程序內已超時的資料不再寫入:在重寫過程中,Redis不會將已經超時的資料寫入新的AOF檔案,這有助於減少不必要的資料記錄。
2、刪除無效命令:舊的AOF檔案中可能包含無效的命令,如del key1
、hdel key2
、srem keys
、set a111
等。重寫過程會識別並刪除這些無效命令,只保留最終資料的寫入命令,從而減小了檔案大小。
3、合併多條寫命令:為了進一步最佳化AOF檔案的大小,重寫過程會將多條寫命令合併為一個。例如,lpush list a
、lpush list b
、lpush list c
可以合併為lpush list a b c
。這種合併減少了命令的數量,進而減小了AOF檔案的大小。
4、防止單條命令過大:對於某些操作型別(如list、set、hash、zset),為了防止單條命令過大造成客戶端緩衝區溢位,重寫過程會以64個元素為界拆分多條命令。雖然這在一定程度上可能增加了命令的數量,但它確保了每條命令的大小都在可控範圍內,有助於維持整體檔案大小的合理性。
總之AOF重寫降低了檔案佔用空間,同時提升載入效能,因為更小的AOF 檔案可以更快地被Redis載入。
AOF重寫關注以下配置:
1、auto-aof-rewrite-percentage
觸發 AOF 重寫的增長百分比。例如,如果當前 AOF 檔案大小是 100MB,並且這個值設定為 100,那麼當 AOF 檔案增長到 200MB 時,說明增長了100%,Redis 會嘗試重寫 AOF。
# 預設值:`100`
`auto-aof-rewrite-percentage 100`
2、auto-aof-rewrite-min-size
AOF 檔案的最小大小,以便觸發重寫。即使 AOF 檔案的增長百分比超過了 auto-aof-rewrite-percentage
設定的值,但如果檔案大小小於這個值,Redis 也不會觸發重寫。
# 預設值:`64mb`
auto-aof-rewrite-min-size 64mb
2.2.4 故障重啟時的資料恢復
當Redis伺服器重啟時,可以載入AOF檔案進行資料恢復。
流程如下:
- 當AOF和RDB檔案同時存在時,優先載入AOF
- 若關閉了AOF(apendonly no),則載入RDB檔案
- 載入AOF/RDB成功之後,redis重啟成功。如果無相關的持久化,則直接啟動成功。
- 如果AOF/RDB 資料恢復存在錯誤,則啟動失敗,並列印輸出錯誤資訊
2.3 RDB和AOF的比較和混合持久化
咱們上一篇介紹了《RDB記憶體快照提供持久化能力》定點快照的使用者,那RDB跟AOF究竟孰優孰慮?
現實情況下,無論使用RDB或者AOF都差點意思。使用 rdb 來恢復記憶體狀態,勢必會丟失一部分資料。使用 AOF 日誌重放,重放對效能有一定的影響,而且在 Redis 例項很大的情況下,需要花費很長的時間。
Redis 4.0 解決了這個問題,才用了一個新的持久化模式——混合持久化,該 混合模式 預設是關閉狀態的。
將 RDB 檔案的內容和 rdb快照時間點之後的增量的 AOF 日誌檔案存在一起。這時候 AOF 日誌不需要再是全量的日誌,而是最近一次快照時間點之後到當下發生的增量 AOF 日誌,通常這部分 AOF 日誌很小。
所以執行有如下順序:
- 查詢rdb內容,如果存在先載入 rdb內容再 重放剩餘的 aof。
- 沒有rdb內容,直接以aof格式重放整個檔案。
這樣快照就不用頻繁的執行,同時由於 AOF 只需要記錄最近一次快照之後的資料,不需要記錄所有的操作,避免了出現單次重放檔案過大的問題。
開啟混合持久化模式:
aof-use-rdb-preamble yes
這個設定告訴Redis在AOF重寫時使用混合持久化模式。當這個選項設定為yes時,重寫後的AOF檔案將包含RDB格式的資料字首和AOF格式的增量修改操作。
總結
- RDB提供了快照模式,記錄某個時間的Redis記憶體狀態。RDB設計了 bgsave 和寫時複製,儘可能避免執行快照期間對讀寫指令的影響,但是頻繁快照會給磁碟帶來壓力以及 fork 阻塞主執行緒。需把握頻率。
- AOF 日誌儲存了 Redis 服務的順序指令序列,透過重放(replay)指令來寫入日誌檔案,並透過寫回策略來避免高頻讀寫給Redis帶來壓力。
- RDB快照的照片時間間隔,必然會帶來資料缺失,如果允許分鐘級別的資料丟失,可以只使用 RDB。
- 如果只用 AOF,寫回策略優先使用 everysec 的配置選項,因為它在可靠性和效能之間取了一個平衡。
- 資料不能丟失時,記憶體快照和 AOF 的混合使用是一個很好的選擇。