相對來說RDB這種持久化模式更加適合較多的場景
以下轉載
Redis支持RDB和AOF兩種持久化機制,持久化功能有效地避免因進程退出造成的數據丟失問題,當下次重啓時利用之前持久化文件即可實現數據恢復。
1. RDB是什麼
RDB持久化是把當前進程數據生成快照保存到硬盤的過程,觸發RDB持久化過程分爲手動觸發和自動觸發。
1.1.1 觸發機制
手動觸發分別對應save和bgsave命令:
**save命令:**阻塞當前Redis服務器,知道RDB過程完成爲止,對於內存比較大的實例會造成長時間阻塞,先上環境不建議使用。運行save命令對應Redis日誌如下:
DB saved on disk
**bgsave命令:**Redis進程執行fork操作創建子進程,RDB持久化過程由子進程負責,完成後自動結束。阻塞只發生在fork階段,一段時間很短。運行bgsave名字對應的Redis日誌如下:
Background saving started by pid 3152
DB saved on disk
RDB: 0MB of memory userd by copy-on-write
Background saving terminated with success
bgsave命令是針對save阻塞問題做的優化。因此Redis內部所有涉及到RDB操作都採用bgsave的方式,而save命令可以廢棄。
Redis內部還存在自動觸發RDB的持久化機制,例如一下場景:
1) 使用save相關配置,如‘save m n’表示m秒之內數據集存在n次修改時,自動觸發bgsave。
2)如果從節點執行全量複製操作,主節點自動執行bgsave生成RDB文件併發送給從節點。
3)執行debug reload命令重新加載Redis時,也會自動觸發save操作。
4)默認情況下執行shutdown命令時,如果沒有開啓AOF持久化功能則自動執行bgsave。
1.1.2 bgsave流程說明
bgsave是主流的觸發RDB持久化方式,下圖是運作流程
-
執行bgsave命令,Redis父進程判斷當前是否存在正在執行的子進程,如只RDB/AOF子進程,如果存在bgsave命令直接返回。
-
父進程執行fork操作創建子進程,fork操作過程中父進程會阻塞,通過info stats命令查看latest_fork_usec選項,可以獲取最近一個fork以操作的耗時,單位爲微秒。
-
父進程仍fork完成後,bgsave命令返回“Background saving started”信息並不再阻塞父進程,可以繼續響應其他命令。
-
子進程創建RDB文件,根據父進程內存生成臨時快照文件,完成後對原有文件進行原子替換。執行lastsave命令可以獲取最後一次生成尺RDB的時間,對應info統計的rdb_last_save_time選項。
-
進程發送信號給父進程衣示完成,父進程更新統計信息,具體見info Persistence下的rdb_*相關選項。
1.1.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 OOM loading DB. Unrecoverable error , aborting now.
這時可以使用Redis提供的redis-check-dump工具檢測RDB文件並獲取對應的錯誤報告
1.1.4 RDB的優缺點
RDB的優點:
-
RDB是一個緊湊壓縮的二進制文件,代表Redis在某一個時間點上的數據快照。非常適合用於備份,全量複製等場景。比如每6小時執行bgsave備份,並把RDB文件拷貝到遠程機器或者文件系統中(如hdfs),用於災難恢復。
-
Redis加載RDB恢復數據遠遠快於AOF方式。
RDB的缺點
-
RDB方式數據沒辦法做到實時持久化/秒級持久化。因爲bgsave每次運行都要執行fork操作創建子進程,屬於重量級操作,頻繁執行成本過高。
-
RDB文件使用特定二進制格式保存,Redis版本演進過程中有多個格式的RDB笨笨,存在老版本Redis服務無法兼容新版RDB格式的問題。
針對RDB不適合實時持久化的問題,Redis提供了AOF持久化方式來解決
2. AOF是什麼
AOF(append only file)持久化:以獨立日誌的方式記錄每次寫命令,重啓時再重新執行AOF文件中命令達到恢復數據的目的。AOF的主要作用是解決了數據持久化的實時性,目前已經是Redis持久化的主流方式。
2.1.1 使用AOF
開啓AOF功能需要設置配置:appendonly yes,默認不開啓。AOF文件通過appendfilename 配置設置,默認文件名是appendonly.aof。保存路徑同RDB持久化方式一致。通過dir配置指定。AOF的工作流程操作:命令寫入(append)、文件同步(sync)、文件重寫(rewrite)、重啓加載(load),工作流程如下:
流程如下:
1) 所有的寫入命令會追加到aof_buf(緩衝區)中。
2) AOF緩衝區根據對應的策略向硬盤做同步操作。
3) 隨着AOF文件越來越大,需要定期對AOF文件進行重寫,達到壓縮的目的。
4) 當Redis服務重啓時,可以加載AOF文件進行數據恢復。瞭解AOF工作流程之後,下面針對每個步驟做詳細介紹。
2.1.2 命令寫入
AOF命令寫入的內容直接是文本協議格式。例如set hello world 這條命令,在AOF緩衝區會追加如下文本:
\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n
介紹關於AOF的連個疑惑:
1) AOF爲什麼直接採用文本協議格式?可能的理由如下:
-
-
文本協議具有很好的兼容性。
-
開啓AOF後,所有寫入命令都包含追加操作,直接採用協議格式,避免二次處理開銷。
-
文本協議具有可讀性,方便直接修改和處理。
-
2) AOF爲什麼把命令追加到aof_buf中?Redis使用單線程響應命令,如果每次寫AOF文件命令都直接追加到硬盤,那麼性能完全取決於當前硬盤負載。縣寫入緩衝區aof_buf中,還有另一個好處,Redis可以提供多種緩衝區同步硬盤的策略,在性能和安全性方面做出平衡。
2.1.3 文件同步
Redis提供了多種AOF緩衝區同步文件策略,由參數appendfsync控制,不同值的含義如表所示
系統調用writ和fsync說明:
-
write操作會處罰延遲寫(delayed write)機制,Linux在內核提供頁緩衝區用來提高硬盤IO性能。write操作在寫入系統緩衝區後直接返回。同步硬盤操作依賴於系統調度機制,列如:緩衝區頁空間寫滿或達到特定時間週期。同步文件之前,如果此時系統故障宕機,緩衝區內數據將丟失。
-
fsync針對單個文件操作(比如AOF文件),做強制硬盤同步,fsync將阻塞知道寫入硬盤完成後返回,保證了數據持久化。
除了write、fsync、Linx還提供了sync、fdatasync操作,具體API說明參見:http://linux.die.net/man/2/write
-
配置爲always時,每次寫入都要同步AOF文件,在一般的STAT硬盤上,Redis只能支持大約幾百TPS寫入,顯然跟Redis高性能特性背道而馳,不建議配置。
-
配置爲no,由於操作系統每次同步AOF文件的週期不可控,而且會極大每次同步硬盤的數據量,雖然提升了性能,但數據安全性無法保證。
-
配置爲everysec,是建議的同步策略,也是默認配置,做到兼顧性能和數據安全性,理論上只有在系統突然宕機的情況下丟失1s的數據。(嚴格來說最多丟失1s數據是不準確)
2.1.4 重寫機制
隨着命令不斷寫入AOF,文件會越來越大,爲了解決這個問題,Redis引入了AOF重寫機制壓縮文件體積。AOF文件重寫是吧Redis進程內的數據轉化爲寫命令同步到新AOF文件的過程。
重寫後的AOF文件爲什麼可以變下?有如下原因:
1) 進程內已經超時的數據不再寫文件。
2)舊的AOF文件含有無效命令,如del key1、 hdel key2、srem keys、set a 111、set a 222等。重寫使用進程內數據直接生成,這樣新的AOF文件只保留最終數據的寫入命令。
3) 多條寫命令可以合併爲一個,如lpush list a、lpush list b、 lpush list c 可以轉化爲: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_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
其中aof_current_size和aof_base_size可以再info Persistence統計信息中查看。
當觸發AOF重寫時,內部做了那些事?下面結合圖介紹它的運行流程:
流程說明:
1)執行AOF重寫請求。
如果當前進程正在執行AOF重寫,請求不執行並返回如下響應:
ERR Background append only file rewriting already in progress
如果當前進程正在執行bgsave操作,重寫命令延遲到bgsave完成後再執行,返回如下響應:
Background append only file rewriting scheduled
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重寫。
2.1.5 重啓加載
AOF和RDB文件都可以用於服務器重啓時的數據恢復。如圖所示,表示Redis持久化文件加載流程:
流程說明:
1) AOF持久化開啓且存在AOF文件時,優先加載AOF文件,打印如下日誌:
DB loaded from append only file: 5.841 seconds
2) AOF關閉或者AOF文件不存在時,加載RDB文件,打印如下日誌:
DB loaded from disk:5.586 seconds
3) 加載AOF/RDB文件城後,Redis啓動成功。
4) AOF/RDB文件存在錯誤時,Redis啓動失敗並打印錯誤信息
個人博客