深入理解Redis系列之持久化

redis持久化配置

redis.conf

// RDB配置
save 900 1
save 300 10
save 60 10000

// AOF配置
appendonly yes

//AOF三種同步方式
# appendfsync always
appendfsync everysec
# appendfsync no

RDB配置對應saveparams參數:

dirty:距離上一次成功執行SAVE或BGSAVE命令之後,伺服器對資料庫狀態進行了多少次修改

在這裡插入圖片描述

RDB和AOF對比

在這裡插入圖片描述

因為AOF更新頻率通常比RDB文件高,所以:

  • 如果伺服器開啟了AOF,那麼伺服器優先使用AOF文件來還原資料庫狀態
  • 只有在AOF關閉狀態,伺服器才使用RDB文件還原資料庫狀態

在這裡插入圖片描述

RDB

RDB手動觸發和自動觸發
  1. 手動觸發分別對應save和bgsave命令
  • SAVE:阻塞redis進程,直到RDB文件創建完畢為止
  • BGSAVE:不阻塞,派生出一個子進程,然後由子進程負責創建RDB文件
  • BGSAVE命令執行時,客戶端發送SAVE或BGSAVE命令會被拒絕,避免父進程和子進程同時執行兩個rdbSave調用,防止產生競爭條件
  • BGSAVE命令執行時,客戶端發送BGSAVE命令會被拒絕,避免兩個父進程同時執行兩個rdbSave調用,防止產生競爭條件
  • BGSAVE命令執行時,客戶端發送BGREWRITEAOF命令會被延遲到BGSAVE命令執行完畢之後執行;若是BGREWRITEAOF命令正在執行,客戶端發送BGSAVE命令會被拒絕

bgsave執行流程(注意第二步,fork操作創建子進程時,父進程會阻塞)
在這裡插入圖片描述

  1. redis內部自動觸發
  • 使用save相關配置,如save m n,表示m秒記憶體在n次修改,自動觸發bgsave
  • 如果從節點執行全量複製操作,主節點自動執行bgsave生成RDB文件並發送給從節點
  • 執行debug reload命令重新載入redis時,也會觸發save操作
  • 默認情況下執行shutdown命令時,如果沒有開啟AOF持久化功能,則自動執行bgsave

RDB文件載入:在伺服器啟動時,檢測到RDB文件存在,自動載入

RDB文件結構

RDB結構:

  • REDIS: 5位元組,保存”REDIS”5個字元
  • db_version:4位元組,記錄RDB文件的版本號

在這裡插入圖片描述

database部分:

database 0 代表0資料庫所有鍵值對數據;database 3 代表3資料庫所有鍵值對數據;

在這裡插入圖片描述

  • SELECTDB:1位元組,代表接下來要讀一個資料庫分區號
    在這裡插入圖片描述

在這裡插入圖片描述

AOF

AOF主要作用:解決數據持久化的實時性

AOF工作流程
  1. 所有寫入命令會追加到aof_buf(緩衝區)中
  2. AOF緩衝區根據對應的同步策略向硬碟做同步操作
  3. 隨著AOF文件越來越大,需要定期對AOF文件進行重寫,達到壓縮的目的
  4. 當Redis伺服器重啟時,可以載入AOF文件進行數據恢復

在這裡插入圖片描述

AOF一些問題
  1. AOF為何直接採用文本協議?
  • 文本協議具有很好的兼容性
  • 開啟AOF後,所有寫入命令都包含追加操作,直接採用文本協議格式,避免二次處理開銷
  • 文本協議具有可讀性,方便直接修改和處理
  1. AOF為何把命令追加到aof_buf中?
  • Redis使用單執行緒響應命令,如果每次寫AOF命令都直接寫入磁碟,那麼性能完全取決當前硬碟負載。另寫入緩衝區,可以提供多種緩衝區同步硬碟的策略,在性能和安全性方面做出平衡
文件同步

在這裡插入圖片描述

重寫機制

AOF重寫作用:

  • 降低文件佔用空間
  • 更小的AOF文件可以更快的被redis載入

重寫機制命令或配置:

  1. 手動觸發:bgrewriteaof命令
  2. 自動觸發配置:
  • auto-aof-rewrite-min-size:AOF重寫時,文件最小體積,默認64MB
  • auto-aof-rewrite-percentage:當前AOF空間(aof_current_size)與上一次重寫後AOF文件空間(aof_base_size)的比值
  • 自動觸發時機:aof_current_size > auto-aof-rewrite-min-size && (aof_current_size – aof_base_size) / aof_base_size >= auto-aof-rewrite-percentage

重寫流程:

    1. 執行AOF重寫請求
    1. 父進程執行fork創建子進程
    1. 1)父進程fork操作完成後,繼續響應其他命令;所有修改命令依然寫入AOF緩衝區,並根據appendfsync策略同步到硬碟,保證原有AOF機制正確 2)由於fork操作運用寫時複製技術,子進程只能共享fork操作時的記憶體數據。由於父進程依然響應命令,Redis使用AOF重寫緩衝區保存這部分數據,防止AOF文件生成期間丟失這部分數據
  • 子進程根據記憶體快照,按照命令合併規則寫入到新的AOF文件。每次批量寫入硬碟數據量由配置aof-rewrite-incremental-fsync控制,默認32MB,防止單次刷盤過多造成硬碟阻塞
  • 新的AOF文件寫入完成後,子進程發送訊號給父進程,父進程更新統計資訊,具體見info persistence下aof_*相關統計
  • 父進程把AOF重寫緩衝區的數據寫入新的AOF文件
  • 使用新的AOF文件替換老文件,完成AOF重寫

在這裡插入圖片描述

重寫AOF文件為什麼可以變小:

  • 進程內已經超時的數據不再寫入文件
  • 舊的AOF文件含有無效命令,如del key1、hdel key2、srem keys、set a111、set a222等;重寫使用進程內數據直接生成,這樣新的AOF文件只保留最終數據寫入命令
  • 多條寫命令可以合併為一個;為防止單條命令過大,造成客戶端緩衝區溢出,對於list、set、hash、zset等類型操作,以64個元素為界拆分為多條。
AOF追加阻塞

流程:

  1. 主執行緒負責寫入AOF緩衝區
  2. AOF執行緒負責每秒執行一次同步磁碟操作,並記錄最近一次同步時間
  3. 主執行緒負責對比上次AOF同步時間:
  • 如果距離上次同步時間小於2s,直接返回
  • 如果距離上次同步時間大於2s,主執行緒將會阻塞,直到同步操作完成

在這裡插入圖片描述

可以發現兩個問題:

  • everysec配置最多丟失2s數據,不是1s
  • 如果系統fsync緩慢,將會導致redis主執行緒阻塞,影響效率

每當AOF追加阻塞事件發生時,在info persistence統計中,aof_delayed_fsync指標會累加

一些命令

save //等待RDB文件創建完畢
bgsave //fork生成子進程

config set dir {newDir} //RDB文件保存在dir目錄下
config set dbfilename {newFileName} //RDB文件名

config set rdbcompression {yew|no}//默認採用LZF演算法進行壓縮,默認開啟,此命令動態進行修改是否進行壓縮

bgrewriteaof //aof文件重寫
redis-cli config set appendonly yes //開啟aof
redis-cli config set save 「」 //關閉rdb
info stats
redis-check-aof –fix

參考:
《Redis開發與運維》
《Redis設計與實現》
//www.redis.cn/documentation.html
//mp.weixin.qq.com/s/GwjQalQ9ZkBbTBtEKpbkMw
//www.redis.cn/topics/persistence.html