redis-數據持久化

數據持久化

Redis支持RDBAOF兩種持久化機制,數據持久化能將數據持久化到磁盤,有效避免因進程退出造成的數據丟失問題,再次啓動時能根據持久化的文件恢復數據。

RDB

RDB持久化是把當前進程數據生成快照保存到硬盤的過程,觸發RDB持久化過程分爲手動觸發和自動觸發。

手動觸發

save命令

save
阻塞當前Redis服務器,直到RDB過程完成爲止,對於內存比較大的實例會造成長時間阻塞,線上環境不建議使用。一般使用bgsave命令異步地執行,但是,如果負責保存數據的後臺子進程出現問題,save可以作爲保存數據的最後手段來使用。

bgsave命令

bgsave
Redis進程執行fork操作創建子進程,Redis進程繼續處理客戶端請求,fork出來的子進程則負責將數據保存到磁盤,然後退出。阻塞只發生在fork階段,一般時間很短。
Redis內部所有涉及RDB的操作都採用bgsave的方式,而save命令已經廢棄。
客戶端可以通過 LASTSAVE 命令查看相關信息,判斷 BGSAVE 命令是否執行成功。

lastsave命令

lastsave
返回最近一次 Redis 成功將數據保存到磁盤上的時間,以 UNIX 時間戳格式表示。

自動觸發

除了執行命令手動觸發之外,Redis內部還存在自動觸發RDB的持久化機制,例如以下場景:

  • 使用save相關配置,如“save m n”。表示m秒內數據集存在n次修改時,自動觸發bgsave。
  • 如果從節點執行全量複製操作,主節點自動執行bgsave生成RDB文件併發送給從節點。
  • 執行debug reload命令重新加載Redis時,也會自動觸發save操作。
  • 默認情況下執行shutdown命令時,如果沒有開啓AOF持久化功能則自動執行bgsave。

流程圖

1
2
3
生成
4
5信號通知父進程
bgsave
父進程
有其他子進程正在執行直接返回
fork
響應其他命令
子進程
生成RDB文件
  • 1執行bgsave命令,Redis父進程判斷當前是否存在正在執行的子進程,如RDB/AOF子進程,如果存在bgsave命令直接返回。
  • 2父進程執行fork操作創建子進程,fork操作過程中父進程會阻塞,通過info stats命令查看latest_fork_usec選項,可以獲取最近一個fork操作的耗時,單位爲微秒。
  • 3父進程fork完成後,bgsave命令返回“Background saving started”信息並不再阻塞父進程,可以繼續響應其他命令。
  • 4子進程創建RDB文件,根據父進程內存生成臨時快照文件,完成後對原有文件進行原子替換。執行lastsave命令可以獲取最後一次生成RDB的時間,對應info統計的rdb_last_save_time選項。
  • 5進程發送信號給父進程表示完成,父進程更新統計信息,具體見info Persistence下的rdb_*相關選項。

RDB文件的處理

保存

更改配置文件

找到redis文件夾下的redis.conf,進行編輯:

dbfilename "指定文件名"
dir "指定路徑"

如下圖:
在這裏插入圖片描述

運行期動態修改

可以登錄redis客戶端後動態修改,在下次持久化數據時會保存到新目錄:

CONFIG SET dbfilename 指定文件名
CONFIG SET dir 指定路徑

當遇到壞盤或磁盤寫滿等情況時,可以通過config set dir {newDir}在線修改文件路徑到可用的磁盤路徑,之後執行bgsave進行磁盤切換,同樣適用於AOF持久化文件。

壓縮

Redis默認採用LZF算法對生成的RDB文件做壓縮處理,壓縮後的文件遠遠小於內存大小,默認開啓。

  • 可以通過修改配置文件
  • 可以通過參數config set rdbcompression {yes|no}動態修改。

檢驗

使用redis-check-rdb工具檢驗rdb文件是否正常:
redis-check-rdb rdb文件
在這裏插入圖片描述

RDB的優缺點

優點

  • RDB是一個緊湊壓縮的二進制文件,代表Redis在某個時間點上的數據快照。非常適用於備份,全量複製等場景。比如每6小時執行bgsave備份,並把RDB文件拷貝到遠程機器或者文件系統中(如hdfs),用於災難恢復。
  • Redis加載RDB恢復數據遠遠快於AOF的方式。

缺點

  • RDB方式數據沒辦法做到實時持久化/秒級持久化。因爲bgsave每次運行都要執行fork操作創建子進程,屬於重量級操作,頻繁執行成本過高。
  • RDB文件使用特定二進制格式保存,Redis版本演進過程中有多個格式的RDB版本,存在老版本Redis服務無法兼容新版RDB格式的問題。

AOF

AOF(append only file)持久化:以獨立日誌的方式記錄每次寫命令,重啓時再重新執行OF文件中的命令達到恢復數據的目的。AOF的主要作用是解決了數據持久化的實時性,目前已經是Redis持久化的主流方式。

使用AOF

開啓AOF功能需要設置配置:appendonly yes,默認不開啓。AOF文件名通過appendfilename配置設置,默認文件名是appendonly.aof。保存路徑同RDB持久化方式一致,通過dir配置指定
AOF的工作流程操作:命令寫入(append)、文件同步(sync)、文件重寫(rewrite)、重啓加載(load)。

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

文件同步

Redis提供了多種AOF緩衝區同步文件策略,由參數appendfsync控制:

可配置值 說明
alwas 命令寫入aof_buf後調用系統fsync操作同步到AOF文件,fsync完成後線程返回
everysec 命令寫入aof_buf後調用系統的write操作,write完成後線程返回。fsync同步文件操作由專門線程每秒調用一次
no 命令寫入aof_buf後調用系統的write操作,不對AOF文件做同步操作,同步硬盤操作由操作系統負責,通常同步週期最長30秒
  • write操作會觸發延遲寫(delayed write)機制。Linux在內核提供頁緩衝區用來提高硬盤IO性能。write操作在寫入系統緩衝區後直接返回。同步硬盤操作依賴於系統調度機制,例如:緩衝區頁空間寫滿或達到特定時間週期。同步文件之前,如果此時系統故障宕機,緩衝區內數據將丟失。
  • fsync針對單個文件操作(比如AOF文件),做強制硬盤同步,fsync將阻塞直到寫入硬盤完成後返回,保證了數據持久化。
  • 配置爲always時,每次寫入都要同步AOF文件,在一般的SATA硬盤上,Redis只能支持大約幾百TPS【Transactions Per Second(每秒傳輸的事物處理個數),即服務器每秒處理的事務數。】寫入,顯然跟Redis高性能特性背道而馳,不建議配置。
  • 配置爲no,由於操作系統每次同步AOF文件的週期不可控,而且會加大每次同步硬盤的數據量,雖然提升了性能,但數據安全性無法保證。
  • 配置爲everysec,是建議的同步策略,也是默認配置,做到兼顧性能和數據安全性。理論上只有在系統突然宕機的情況下丟失1秒的數據(嚴格來說是2秒)。

重寫機制

隨着命令不斷寫入AOF,文件會越來越大,爲了解決這個問題,Redis引入AOF重寫機制壓縮文件體積。AOF文件重寫是把Redis進程內的數據轉化爲寫命令同步到新AOF文件的過程。
重寫後的AOF文件爲什麼可以變小?有如下原因:

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

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

觸發方式

手動觸發

直接調用bgrewriteaof命令

自動觸發

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

  • auto-aof-rewrite-min-size:表示運行AOF重寫時文件最小體積,默認爲64MB。
  • auto-aof-rewrite-percentage:代表當前AOF文件空間(aof_current_size)和上一次重寫後AOF文件空間(aof_base_size)的比值,默認100。

在這裏插入圖片描述

自動觸發時機=aof_current_size>auto-aof-rewrite-min-size&&(aof_current_size - aof_base_size)/aof_base_size>=auto-aof-rewrite-percentage
其中aof_current_size和aof_base_size可以在info Persistence統計信息中查看。

重寫觸發流程

1
2
3.1
3.2
創建
4
5.2
5.1信號通知父進程
5.3
bgrewriteaof
父進程
fork
aof_buf
aof_rewrite_buf
子進程
新AOF文件
舊AOF文件
  • 1 執行AOF重寫請求。如果當前進程正在執行AOF重寫,請求不執行。如果當前進程正在執行bgsave操作,重寫命令延遲到bgsave完成之後再執行。
  • 2父進程執行fork創建子進程,開銷等同於bgsave過程。
  • 3.1主進程fork操作完成後,繼續響應其他命令。 所有修改命令依然寫入AOF緩衝區並根據appendfsync策略同步到硬盤, 保證原有AOF機制正確性。
  • 3.2由於fork操作運用寫時複製技術, 子進程只能共享fork操作時的內存數據。 由於父進程依然響應命令, Redis使用“AOF重寫緩衝區”保存這部分新數據, 防止新AOF文件生成期間丟失這部分數據。
  • 4子進程根據內存快照, 按照命令合併規則寫入到新的AOF文件。 每次批量寫入硬盤數據量由配置aof-rewrite-incremental-fsync控制,默認爲32MB,防止單次刷盤數據過多造成硬盤阻塞。
  • 5.1新AOF文件寫入完成後, 子進程發送信號給父進程, 父進程更新統計信息, 具體見info persistence下的aof_*相關統計。
  • 5.2父進程把AOF重寫緩衝區的數據寫入到新的AOF文件。
  • 5.3使用新AOF文件替換老文件, 完成AOF重寫。

爲什麼需要執行重寫呢?1>2>3.1這條線已經實現了實時持久化,執行其餘的流程不是多餘的嗎?並不多餘,上文說過重寫就是解決持久化文件越來越大的問題。

重啓加載

AOF和RDB文件都可以用於服務器重啓時的數據恢復。

no
yes
no
yes
no
yes
yes
no
redis啓動
開啓AOF?
存在RDB?
存在AOF?
加載AOF
啓動成功
加載RDB
成功?
啓動失敗
  1. AOF持久化開啓且存在AOF文件時,優先加載AOF文件。
  2. AOF關閉或AOF文件不存在時,加載RDB文件。
  3. 加載AOF/RDB文件成功後,redis啓動成功。
  4. AOF/RDB文件存在錯誤時,Redis啓動失敗並打印錯誤信息。

文件校驗

使用redis-check-aof工具檢驗rdb文件是否正常:
redis-check-aof aof文件名
在這裏插入圖片描述

對於錯誤格式的AOF文件, 先進行備份, 然後採用redis-check-aof--fix命令進行修復, 修復後使用diff-u對比數據的差異, 找出丟失的數據, 有些可以人工修改補全。
AOF文件可能存在結尾不完整的情況, 比如機器突然掉電導致AOF尾部文件命令寫入不全。 Redis爲我們提供了aof-load-truncated配置來兼容這種情況, 默認開啓。

參考資料:

  • redis開發與運維
  • http://redisdoc.com/index.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章