1. 程式人生 > 程式設計 >Redis-AOF持久化

Redis-AOF持久化

RDBAOF 區別在於: 前者儲存資料庫快照,持久化所有鍵值對,後者通過儲存 寫命令 保證資料庫的狀態.

什麼是 AOF ?

AOF 持久化通過儲存伺服器執行的寫命令實現,進行恢復時通過重放 AOF 檔案中的寫命令,來保證資料安全.就像 mysqlbinlog 一樣.

開啟 AOF

通過在 redis.conf 中將 appendonly 設為 yes 即可

# redis.conf
appendonly yes
# 設定 aof 檔名字
appendfilename "appendonly.aof"
# Redis支援三種不同的刷寫模式:
# appendfsync always #每次收到寫命令就立即強制寫入磁碟,是最有保證的完全的持久化,但速度也是最慢的,一般不推薦使用。
appendfsync everysec #每秒鐘強制寫入磁碟一次,在效能和持久化方面做了很好的折中,是受推薦的方式。 # appendfsync no #完全依賴OS的寫入,一般為30秒左右一次,效能最好但是持久化最沒有保證,不被推薦。 複製程式碼

AOF 檔案格式

AOF 檔案格式以 redis 命令請求協議為標準的,*.aof 檔案可以直接開啟.

redis設計與實現-aof格式

AOF 持久化過程

命令追加 append

redis 執行完客戶端的寫命令後,會將該命令以協議的格式寫入到 aof_buf 中.該屬性為 redisServer 中的一個.

#src/server.h
struct redisServer
{
.... sds aof_buf; /* AOF buffer,written before entering the event loop */ } 複製程式碼

AOF 寫入同步

redis 的服務程式是一個 事件迴圈 - event loop,每次迴圈大概會做三件事.

  1. 檔案事件: 接收客戶端的命令,返回結果
  2. 時間事件: 執行系統的定時任務(serverCron),完成漸進 rehash 擴容之類的操作
  3. aof flush: 是否將 aof_buf 中的內容寫入檔案中
# 虛擬碼
def eventloop():
 while true:
 	processFileEvents() # 處理命令
processTimeEvents() # 處理定時任務 flushAppendOnlyFile() # 處理 aof 寫入 複製程式碼

flushAppendOnlyFile 中的動作是否執行是根據一個配置決定的.

appendfsync

該配置有幾個值可選,預設是 everysec.

  1. always: 總是寫入.只要程式執行到這一步了,就將 aof_buf 中命令協議寫入到檔案
  2. everysec: 每秒寫入. 每次執行前會先判斷是否與上次寫入間隔一秒,再次同步時通過 一個執行緒 專門執行
  3. no: 不寫入. 命令寫入 aof_buf 後由作業系統決定何時同步到檔案

fsync: 現代作業系統為了提高檔案讀寫的效率,通常會將 write 函式寫入的資料快取在記憶體中,等到快取空間填滿或者超過一定時限,再將其寫入磁碟.這樣的問題在於宕機時快取中的資料就無法恢復.所以作業系統提供了 fsync/fdatasync 兩個函式,強製作業系統將資料立即寫入磁碟,保證資料安全.兩函式區別在於: 前者會更新檔案的屬性,後者只更新資料.

三種模式在效能和資料上都有相對的優缺點. always 模式資料安全性更強,畢竟每次都是直接寫入,但是就會影響效能.磁碟讀寫是比較慢的. everysec 模式效能較好,但會丟失一秒內的快取資料. no 模式就完全取決於作業系統了.

AOF 還原資料

redis設計與實現-aof還原資料

AOF 重寫

AOF 重寫的意思其實就是對單個命令的多個操作進行整理,留下最終態的執行命令來減少 aof 檔案的大小.你可以想象一下執行 1w 次 incr 操作,寫入 aof 1w 次的場景.

觸發條件

AOF 重寫可以自動觸發.通過配置 auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage,滿足條件就會自動重寫.具體可以檢視官方的 redis.conf

重寫過程

  1. 建立子程式,根據記憶體裡的資料重寫aof,儲存到temp檔案
  2. 此時主程式還會接收命令,會將寫操作追加到舊的aof檔案中,並儲存在server.aof_rewrite_buf_blocks中,通過管道傳送給子程式存在server.aof_child_diff中,最後追加到temp檔案結尾
  3. 子程式重寫完成後退出,主程式根據子程式退出狀態,判斷成功與否。成功就將剩餘的server.aof_rewrite_buf_blocks追加到temp file中,然後rename()覆蓋原aof檔案

重寫的過程中主程式還是會一直接受客戶端的命令,所以重寫子程式與主程式肯定會存在資料不一致的情況.redis針對這種情況作出瞭解決方案: 新增一個 aof_rewrite_buf_blocks,aof 寫入命令時,不僅寫入到 aof_buf,如果正在重寫,那麼也寫入到 aof_rewrite_buf_blocks 中,這樣在子程式重寫完畢後,可以將 aof_rewrite_buf_blocks 的命令追加到新檔案中,保證資料不丟失.

rename 操作是原子的,也是唯一會造成主程式阻塞的操作.

參考

  1. redis.io/topics/pers…
  2. youjiali1995.github.io/redis/persi…