天天看點

7、Redis持久化(RDB、AOF)、scan操作

Redis雖然是個記憶體資料庫,但是Redis支援RDB和AOF兩種持久化機制,将資料寫住磁盤,可以有效避免因程序退出造成的資料丢失問題,當下次重新開機時利用之前持久化的檔案即可實作資料恢複。

一、RDB

RDB持久化是把目前程序資料生成快照儲存到硬碟的過程,觸發RDB持久化過程分為手動觸發和自動觸發。

1、觸發機制

手動觸發

可以用save和bgsave指令

save指令:阻塞目前Redis伺服器,直到RDB過程完成為止,對于記憶體比較大的執行個體會造成長時間阻塞,線上環境不建議使用。

bgsave指令:Redis程序執行fork操作建立子程序,RDB持久化過程由子程序負責,完成後自動結束。阻塞隻發生在fork階段,一般時間很短。

bgsave指令是針對save阻塞問題做的優化,是以Redis内部所涉及RDB的操作都采用的是bgsave

自動觸發

  1. 使用save相關配置,如“save m n”。表示m秒内資料集存在n次修改時,自動觸發bgsave。
  2. 如果從節點執行全量複制操作,主節點自動執行bgsave生成RDB檔案并發送給從節點
  3. 執行debug reload指令重新加載Redis時,也會自動觸發save操作
  4. 預設情況下執行shutdown指令時,如果沒有開啟AOF持久化功能則自動執行bgsave

關閉RDB持久化:将配置檔案中的save配置改為 save “”

2、bgsave執行過程

  1. 執行 bgsave 指令,Redis 父程序判斷目前是否存在正在執行的子程序,如RDB/AOF 子程序,如果存在,bgsave 指令直接傳回。
  2. 父程序執行 fork 操作建立子程序,fork 操作過程中父程序會阻塞,通過 info stats 指令檢視 latest_fork_esec 選項,可以擷取最近一個 fork 操作的耗時,機關為微秒。
  3. 父程序 fork 完成後,bgsave 指令傳回“Background saving started”資訊并不再阻塞父程序,可以繼續響應其他指令。
  4. 子程序建立 RDB 檔案,根據父程序記憶體生成臨時快照檔案,完成後對原有檔案進行原子替換。執行 lastsave 指令可以擷取最後一次生成 RDB 的時間,對應info 統計的 rdb_last_save_time 選項。
  5. 程序發送信号給父程序表示完成,父程序更新統計資訊,具體見 info Persistence 下的 rdb_*相關選項。

3、RDB檔案

RDB 檔案儲存在 dir 配置指定的目錄下,檔案名通過 dbfilename 配置指定。可以通過執行 config set dir {newDir}和 config set dbfilename (newFileName}運作期 動态執行,當下次運作時 RDB 檔案會儲存到新目錄。

Redis 預設采用 LZF 算法對生成的 RDB 檔案做壓縮處理,壓縮後的檔案遠遠小于記憶體大小,預設開啟,可以通過參數 config set rdbcompression { yes |no}動态修改。

如果 Redis 加載損壞的 RDB 檔案時拒絕啟動,并列印如下日志:

# Short read or 0OM loading DB. Unrecoverable error,aborting now.

這時可以使用 Redis 提供的 redis-check-dump 工具檢測 RDB 檔案并擷取對應的錯誤報告。

4、RDB的優缺點

RDB的優點:

RDB 是一個緊湊壓縮的二進制檔案,代表 Redis 在某個時間點上的資料快照。非常适用于備份,全量複制等場景。

Redis 加載 RDB 恢複資料遠遠快于 AOF 的方式。

RDB的缺點:

RDB 方式資料沒辦法做到實時持久化/秒級持久化。因為 bgsave 每次運作都要執行 fork 操作建立子程序,屬于重量級操作,頻繁執行成本過高。

RDB 檔案使用特定二進制格式儲存Redis 版本演進過程中有多個格式的 RDB版本,存在老版本 Redis 服務無法相容新版 RDB 格式的問題。

針對 RDB 不适合實時持久化的問題,Redis 提供了 AOF 持久化方式來解決。

二、AOF

AOF(append only file):以獨立日志的方式記錄每次寫指令,重新開機時再重新執行AOF檔案中的指令達到恢複資料的目的。AOF主要作用是解決了資料持久化的實時性,目前已是Redis持久化的主流方式。

1、使用AOF

AOF預設是不開啟,如需開啟AOF則設定配置:appendonly yes,AOF檔案名通過appendfilename 配置設定,預設檔案名是 appendonly.aof。。儲存路徑同 RDB 持久化方式一緻,通過 dir 配置指定。

2、AOF工作流程

AOF的工作流程操作:指令寫入(append)—>檔案同步(sync)—>檔案重寫(rewrite)—>重新開機加載(load)

7、Redis持久化(RDB、AOF)、scan操作

1)所有的寫入指令會追加到 aof_buf(緩沖區)中。

2)AOF 緩沖區根據對應的政策向硬碟做同步操作

3)随着 AOF 檔案越來越大,需要定期對 AOF 檔案進行重寫,達到壓縮的目的。

4)當 Redis 伺服器重新開機時,可以加載 AOF 檔案進行資料恢複。

Redis 提供了多種 AOF 緩沖區同步檔案政策,由參數 appendfsync 控制:

  • always:指令寫人 aof_buf 後調用系統 fsync 操作同步到 AOF 檔案,fsync 完成後線程傳回指令 fsync 同步檔案。(預設方式)
  • everysec:寫人 aof_buf 後調用系統 write 操作,write 完成後線程傳回。操作由專門線程每秒調用一次 fsync 指令。
  • no:寫入 aof_buf 後調用系統 write 操作,不對 AOF 檔案做 fsync 同步,同步硬碟操作由作業系統負責,通常同步周期最長 30 秒

3、重寫機制

随着指令不斷寫入 AOF,檔案會越來越大,為了解決這個問題,Redis 引入AOF 重寫機制壓縮檔案體積。AOF 檔案重寫是把 Redis 程序内的資料轉化為寫指令同步到新 AOF 檔案的過程。

重寫後的 AOF 檔案為什麼可以變小:

  1. 程序内已經逾時的資料不再寫入檔案。
  2. 舊的 AOF 檔案含有無效指令,如 set a 111、set a 222 等。重寫使用程序内資料直接生成,這樣新的 AOF 檔案隻保留最終資料的寫入指令。
  3. 多條寫指令可以合并為一個,如:lpush list a、lpush list b、lpush listc 可以轉化為: lpush list a b c。為了防止單條指令過大造成用戶端緩沖區溢出,對于 list、set、hash、zset 等類型操作,以 64 個元素為界拆分為多條

AOF 重寫降低了檔案占用空間,除此之外,另一個目的是:更小的 AOF 檔案可以更快地被 Redis 加載。

AOF重寫可以手動觸發和自動觸發:

手動觸發:直接調用 bgrewriteaof 指令。

自動觸發:根據 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 參數确定自動觸發時機。

  • auto-aof-rewrite-min-size:表示運作 AOF 重寫時檔案最小體積,預設為 64MB。
  • auto-aof-rewrite-percentage:代表目前 AOF 檔案空間(aof_currentsize)和上一次重寫後 AOF 檔案空間(aof_base_size)的比值。

4、重新開機加載

AOF 和 RDB 檔案都可以用于伺服器重新開機時的資料恢複。redis 重新開機時加載AOF 與 RDB 的順序是怎樣的:

  1. 當AOF和RDB檔案同時存在時,優先加載AOF
  2. 若關閉了AOF,加載RDB檔案
  3. 加載AOF/RDB成功,redis重新開機成功
  4. AOF/RDB存在錯誤,啟動失敗列印錯誤資訊
    7、Redis持久化(RDB、AOF)、scan操作

5、檔案校驗

加載損壞的 AOF 檔案時會拒絕啟動,對于錯誤格式的 AOF 檔案,先進行備份,然後采用 redis-check-aof --fix 指令進行修複,對比資料的差異,找出丢失的資料,有些可以人工修改補全。

AOF 檔案可能存在結尾不完整的情況,比如機器突然掉電導緻 AOF 尾部檔案指令寫入不全。Redis 為我們提供了 aof-load-truncated 配置來相容這種情況,預設開啟。加載 AOF 時當遇到此問題時會忽略并繼續啟動

三、scan

keys指令執行時會周遊所有鍵,可能會帶來阻塞問題,而scan采用漸進式周遊的方式,每次隻掃描字典中的一部分鍵。

scan cursor [match pattern] [count number]
           
  • cursor 是必需參數,實際上 cursor 是一個遊标,第一次周遊從 0 開始,每次scan 周遊完都會傳回目前遊标的值,直到遊标值為 0,表示周遊結束。
  • Match pattern是可選參數,它的作用的是做模式的比對,這點和keys的模式比對很像。
  • Count number 是可選參數,它的作用是表明每次要周遊的鍵個數,預設值是10,此參數可以适當增大。
    7、Redis持久化(RDB、AOF)、scan操作
    得到結果 cursor 變為 0,說明所有的鍵已經被周遊過了。

除了 scan 以外,Redis 提供了面向哈希類型、集合類型、有序集合的掃描周遊指令,解決諸如 hgetall、smembers、zrange 可能産生的阻塞問題,對應的指令分别是 hscan、sscan、zscan,它們的用法和 scan 基本類似。

漸進式周遊可以有效的解決 keys 指令可能産生的阻塞問題,但是 scan 并非完美無瑕,如果在 scan 的過程中如果有鍵的變化(增加、删除、修改),那麼周遊效果可能會碰到如下問題:新增的鍵可能沒有周遊到,周遊出了重複的鍵等情況,也就是說 scan 并不能保證完整的周遊出來所有的鍵。