Redis持久化——AOF机制详解
在運行情況下,Redis 以數據結構的形式將數據維持在內存中,為了讓這些數據在 Redis 重啟之后仍然可用,需要將數據寫入持久存儲
持久化是指將數據寫入持久存儲,例如固態磁盤(SSD)
Redis 提供了一系列持久化選項。這些包括:
- RDB(Redis Database):將數據庫的快照(snapshot)以二進制的方式保存到磁盤中
- AOF(Append Only File):以協議文本的方式,將所有對數據庫進行過寫入的命令(及其參數)記錄到 AOF 文件,以此達到記錄數據庫狀態的目的
- RDB + AOF:RDB和AOF混合方式(4.0版本)
RDB詳解見Redis持久化——RDB機制詳解
AOF
本文首先介紹 AOF 功能的運作機制,了解命令是如何被保存到 AOF 文件里的,觀察不同的 AOF 保存模式對數據的安全性、以及 Redis 性能的影響。
之后會介紹從 AOF 文件中恢復數據庫狀態的方法,以及該方法背后的實現機制。
最后還會介紹對 AOF 進行重寫以調整文件體積的方法,并研究這種方法是如何在不改變數據庫狀態的前提下進行的
AOF文件使用網絡通訊協議的格式來保存這些命令
AOF例子
若執行以下命令:
redis> RPUSH list 1 2 3 4 (integer) 4redis> LRANGE list 0 -1 1) "1" 2) "2" 3) "3" 4) "4"redis> KEYS * 1) "list"redis> RPOP list "4"那么其中兩條對數據庫有修改的寫入命令就會被同步到 AOF 文件中:
RPUSH list 1 2 3 4RPOP list上面列舉的兩個命令在 AOF 文件實際保存如下:
*2 $6 SELECT $1 0 *6 $5 RPUSH $4 list $1 1 $1 2 $1 3 $1 4 *2 $4 RPOP $4 list除了 SELECT 命令是 AOF 程序自己加上去的之外, 其他命令都是之前我們在終端里執行的命令
*表示后面語句的詞個數,$表示后面詞的字節數
AOF同步步驟
同步命令到 AOF 文件的整個過程可以分為三個階段:
命令傳播
當一個 Redis 客戶端需要執行命令時,它通過網絡連接,將協議文本發送給 Redis 服務器
比如說,要執行命令SET KEY VALUE,客戶端將向服務器發送文本*3\r\n$3\r\nSET\r\n$3\r\nKEY\r\n$5\r\nVALUE\r\n
服務器在接到客戶端的請求之后,它會根據協議文本的內容,選擇適當的命令函數,并將各個參數從字符串文本轉換為 Redis 字符串對象(StringObject)
每當命令函數成功執行之后, 命令參數都會被傳播到 AOF 程序, 以及 REPLICATION 程序
緩存追加
當命令被傳播到 AOF 程序之后,程序會根據命令以及命令的參數,將命令從字符串對象轉換回原來的協議文本
緩存追加過程可以分為以下三步:
協議文本生成之后,它會被追加到redis.h/redisServer結構的aof_buf末尾
redisServer結構維持著 Redis 服務器的狀態,aof_buf域則保存著所有等待寫入到 AOF 文件的協議文本
struct redisServer {// 其他域...sds aof_buf;// 其他域... };文件寫入和保存
每當服務器常規任務函數被執行、或者事件處理器被執行時,aof.c/flushAppendOnlyFile函數都會被調用,這個函數執行以下兩個工作:
- WRITE:根據條件,將aof_buf中的緩存寫入到 AOF 文件
- SAVE:根據條件,調用fsync或fdatasync函數,將 AOF 文件保存到磁盤中
兩個步驟都需要根據一定的條件來執行 而這些條件由 AOF 所使用的保存模式來決定。以下會介紹 AOF 所使用的三種保存模式,以及在這些模式下,步驟WRITE和SAVE的調用條件
AOF 保存模式
Redis 目前支持三種 AOF 保存模式
- Always,同步寫回:每個寫命令執行完,立馬同步地將日志寫回磁盤
- Everysec,每秒寫回:每個寫命令執行完,只是先把日志寫到AOF文件的內存緩沖區,每隔一秒把緩沖區中的內容寫入磁盤
- No,操作系統控制的寫回:每個寫命令執行完,只是先把日志寫到AOF文件的內存緩沖區,由操作系統決定何時將緩沖區內容寫回磁盤
AOF重寫
根據鍵的類型,使用適當的寫入命令來重現鍵的當前值,這就是 AOF 重寫的實現原理
所謂的“重寫”其實是一個有歧義的詞語,實際上 AOF 重寫并不需要對原有的 AOF 文件進行任何寫入和讀取,它針對的是數據庫中鍵的當前值
AOF后臺重寫
AOF 重寫是一個有歧義的名字,實際的重寫工作是針對數據庫的當前值來進行的,程序既不讀寫、也不使用原有的 AOF 文件
AOF 后臺重寫,是為了避免主進程被阻塞,無法處理請求,所以采用主進程fork出子進程,用于 AOF 重寫。為了避免在 AOF 重寫期間新命令對現有數據的修改導致的不一致問題,Redis 增加了一個AOF 重寫緩存,這個緩存在fork出子進程之后開始啟用,Redis 主進程在接到新的寫命令之后,除了會將這個寫命令的協議內容追加到現有的 AOF 文件之外,還會追加到這個緩存中
換言之, 當子進程在執行 AOF 重寫時, 主進程需要執行以下三個工作:
當子進程完成 AOF 重寫之后,它會向主進程發送一個完成信號,主進程在接到完成信號之后,會調用一個信號處理函數,并完成以下工作:
以上就是 AOF 后臺重寫, 也即是BGREWRITEAOF命令的工作原理
AOF優缺點
- 優點
- 擁有不同的fsync策略,fsync是使用后臺線程執行的,寫入性能很好
- AOF是一個僅追加日志,沒有查找和斷電時的損壞問題。即使由于某種原因(磁盤已滿或其他原因)日志以寫入一半的命令結束,redis-check-aof工具也能夠輕松修復它
- 當 AOF 變得太大時,Redis 能夠在后臺自動重寫 AOF
- AOF 以易于理解和解析的格式包含一個接一個地記錄所有操作的日志,使得導出和恢復十分簡單
- 缺點
-
對于相同的數據集,AOF 文件通常比等效的 RDB 文件大
-
根據確切的 fsync 策略,AOF 可能比 RDB 慢
Redis < 7.0
-
如果在重寫期間有對數據庫的寫入,AOF 會使用大量內存
-
重寫期間到達的所有寫入命令都會寫入磁盤兩次
-
Redis 可能會在重寫結束時凍結寫入并將這些寫入命令同步到新的 AOF 文件
-
RDB和AOF混合方式(4.0版本)
Redis 4.0 中提出了一個混合使用 AOF 日志和內存快照的方法。簡單來說,內存快照以一定的頻率執行,在兩次快照之間,使用 AOF 日志記錄這期間的所有命令操作。
這樣一來,快照不用很頻繁地執行,這就避免了頻繁 fork 對主線程的影響。而且,AOF 日志也只用記錄兩次快照間的操作,也就是說,不需要記錄所有操作了,因此,就不會出現文件過大的情況了,也可以避免重寫開銷。
如下圖所示,T1 和 T2 時刻的修改,用 AOF 日志記錄,等到第二次做全量快照時,就可以清空 AOF 日志,因為此時的修改都已經記錄到快照中了,恢復時就不再用日志了。
這個方法既能享受到 RDB 文件快速恢復的好處,又能享受到 AOF 只記錄操作命令的簡單優勢, 實際環境中用的很多。
參考資料:
總結
以上是生活随笔為你收集整理的Redis持久化——AOF机制详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑怎么修改html5,详细教你怎么设置
- 下一篇: 猿创征文 | MySQL从基础到高级