12.02 Redis-AOF持久化

RDB 和 AOF 區別在於: 前者保存數據庫快照,持久化所有鍵值對,後者通過保存 寫命令

保證數據庫的狀態.

什麼是 AOF ?

AOF 持久化通過保存服務器執行的寫命令實現,進行恢復時通過重放 AOF 文件中的寫命令,來保證數據安全.就像 mysql 的 binlog 一樣.

開啟 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:

\tprocessFileEvents() # 處理命令
\tprocessTimeEvents() # 處理定時任務
\tflushAppendOnlyFile() # 處理 aof 寫入
\t
複製代碼

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-size 和 auto-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 操作是原子的,也是唯一會造成主進程阻塞的操作.


分享到:


相關文章: