redis持久化機制

持久化的緣由

不少時候咱們須要持久化數據也就是將內存中的數據寫入到硬盤裏面,大部分緣由是爲了以後重用數據(好比重啓機器、機器故障以後回覆數據),或者是爲了防止系統故障而將數據備份到一個遠程位置。數據庫

Redis的數據是存在內存中的,若是Redis發生宕機,那麼數據會所有丟失,所以必須提供持久化機制。安全

持久化方式

  • RDB 快照模式
  • AOF 只追加文件日誌模式

Redis 的持久化機制有兩種,第一種是快照(RDB),第二種是AOF日誌。服務器

快照是一次全量備份app

AOF 日誌是連續的增量備份。工具

快照是內存數據的二進制序列化形式,在存儲上很是緊湊,而AOF日誌記錄的是內存數據修改的指令記錄文本。AOF日誌在長期的運行過程當中會變的無比龐大,數據庫重啓時須要加載AOF日誌進行指令重放,這個時間就會無比漫長。因此須要按期進行 AOF 重寫,給 AOF 日誌進行瘦身。性能

RDB是經過Redis主進程fork子進程,讓子進程執行磁盤 IO 操做來進行 RDB 持久化,AOF 日誌存儲的是 Redis 服務器的順序指令序列,AOF 日誌只記錄對內存進行修改的指令記錄.即RDB記錄的是數據,AOF記錄的是指令優化

快照(snapshotting)持久化(RDB)

Redis能夠經過建立快照來得到存儲在內存裏面的數據在某個時間點上的副本。Redis建立快照以後,能夠對快照進行備份,能夠將快照複製到其餘服務器從而建立具備相同數據的服務器副本(Redis主從結構,主要用來提升Redis性能),還能夠將快照留在原地以便重啓服務器的時候使用操作系統

快照持久化是Redis默認採用的持久化方式,在redis.conf配置文件中默認有此下配置:線程

save 900 1           #在900秒(15分鐘)以後,若是至少有1個key發生變化,Redis就會自動觸發BGSAVE命令建立快照。

save 300 10          #在300秒(5分鐘)以後,若是至少有10個key發生變化,Redis就會自動觸發BGSAVE命令建立快照。

save 60 10000        #在60秒(1分鐘)以後,若是至少有10000個key發生變化,Redis就會自動觸發BGSAVE命令建立快照。

根據配置,快照將被寫入dbfilename選項指定的文件裏面,並存儲在dir選項指定的路徑上面。若是在新的快照文件建立完畢以前,Redis、系統或者硬件這三者中的任意一個崩潰了,那麼Redis將丟失最近一次建立快照寫入的全部數據

舉個例子:假設Redis的上一個快照是2:35開始建立的,而且已經建立成功。下午3:06時,Redis又開始建立新的快照,而且在下午3:08快照建立完畢以前,有35個鍵進行了更新。若是在下午3:06到3:08期間,系統發生了崩潰,致使Redis沒法完成新快照的建立工做,那麼Redis將丟失下午2:35以後寫入的全部數據。另外一方面,若是系統剛好在新的快照文件建立完畢以後崩潰,那麼Redis將丟失35個鍵的更新數據。

建立快照的辦法有以下幾種:

  • BGSAVE命令: 客戶端向Redis發送 BGSAVE命令 來建立一個快照。對於支持BGSAVE命令的平臺來講(基本上全部平臺支持,除了Windows平臺),Redis主線程會fork一個子進程,而後子進程負責將快照寫入硬盤,而父進程則繼續處理命令請求
  • SAVE命令: 客戶端還能夠向Redis發送 SAVE命令 來建立一個快照.接到SAVE命令的Redis服務器在快照建立完畢以前不會再響應任何其餘命令。SAVE命令不經常使用,咱們一般只會在沒有足夠內存去執行BGSAVE命令的狀況下,又或者即便等待持久化操做執行完畢也無所謂的狀況下,纔會使用這個命令。
  • save選項: 若是用戶設置了save選項(通常會默認設置),好比 save 60 10000,那麼從Redis最近一次建立快照以後開始算起,當「60秒以內有10000次寫入」這個條件被知足時,Redis就會自動觸發BGSAVE命令。
  • SHUTDOWN命令: 當Redis經過SHUTDOWN命令接收到關閉服務器的請求時,或者接收到標準TERM信號時,會執行一個SAVE命令,阻塞全部客戶端,再也不執行客戶端發送的任何命令,並在SAVE命令執行完畢以後關閉服務器
  • 一個Redis服務器鏈接到另外一個Redis服務器: 當一個Redis服務器鏈接到另外一個Redis服務器,並向對方發送SYNC命令來開始一次複製操做的時候,若是主服務器目前沒有執行BGSAVE操做,或者主服務器並不是剛剛執行完BGSAVE操做,那麼主服務器就會執行BGSAVE命令

若是系統真的發生崩潰,用戶將丟失最近一次生成快照以後更改的全部數據。所以,快照持久化只適用於即便丟失一部分數據也不會形成一些大問題的應用程序。不能接受這個缺點的話,能夠考慮AOF持久化。

優勢

  • 對性能影響最小。Redis在保存RDB快照時會fork出子進程進行,幾乎不影響Redis處理客戶端請求的效率。

  • 每次快照會生成一個完整的數據快照文件,因此能夠輔以其餘手段保存多個時間點的快照(例如把天天0點的快照備份至其餘存儲媒介中),做爲很是可靠的災難恢復手段。

  • 使用RDB文件進行數據恢復比使用AOF要快不少。

缺點

  • 快照是按期生成的,因此在Redis crash時或多或少會丟失一部分數據。

  • 若是數據集很是大且CPU不夠強(好比單核CPU),Redis在fork子進程時可能會消耗相對較長的時間(長至1秒),影響這期間的客戶端請求。

AOF(append-only file)持久化

與快照持久化相比,AOF持久化 的實時性更好,所以已成爲主流的持久化方案。默認狀況下Redis沒有開啓AOF(append only file)方式的持久化,能夠經過appendonly參數開啓:

appendonly yes

開啓AOF持久化後每執行一條會更改Redis中的數據的命令,Redis就會將該命令寫入硬盤中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是經過dir參數設置的,默認的文件名是appendonly.aof。

在Redis的配置文件中存在三種不一樣的 AOF 持久化方式,它們分別是:

appendfsync always    #每次有數據修改發生時都會寫入AOF文件,這樣會嚴重下降Redis的速度
appendfsync everysec  #每秒鐘同步一次,顯示地將多個寫命令同步到硬盤
appendfsync no        #讓操做系統決定什麼時候進行同步

appendfsync always 能夠實現將數據丟失減到最少,不過這種方式須要對硬盤進行大量的寫入並且每次只寫入一個命令,十分影響Redis的速度。另外使用固態硬盤的用戶謹慎使用appendfsync always選項,由於這會明顯下降固態硬盤的使用壽命。

爲了兼顧數據和寫入性能,用戶能夠考慮 appendfsync everysec選項 ,讓Redis每秒同步一次AOF文件,Redis性能幾乎沒受到任何影響。並且這樣即便出現系統崩潰,用戶最多隻會丟失一秒以內產生的數據。當硬盤忙於執行寫入操做的時候,Redis還會優雅的放慢本身的速度以便適應硬盤的最大寫入速度。

appendfsync no 選項通常不推薦,這種方案會使Redis丟失不定量的數據並且若是用戶的硬盤處理寫入操做的速度不夠的話,那麼當緩衝區被等待寫入的數據填滿時,Redis的寫入操做將被阻塞,這會致使Redis的請求速度變慢。

雖然AOF持久化很是靈活地提供了多種不一樣的選項來知足不一樣應用程序對數據安全的不一樣要求,但AOF持久化也有缺陷——AOF文件的體積太大

AOF 重寫

Redis提供了AOF rewrite功能,能夠重寫AOF文件,只保留可以把數據恢復到最新狀態的最小寫操做集。

AOF雖然在某個角度能夠將數據丟失下降到最小並且對性能影響也很小,可是極端的狀況下,體積不斷增大的AOF文件極可能會用完硬盤空間。另外,若是AOF體積過大,那麼還原操做執行時間就可能會很是長。

爲了解決AOF體積過大的問題,用戶能夠向Redis發送 BGREWRITEAOF命令 ,這個命令會經過移除AOF文件中的冗餘命令來重寫(rewrite)AOF文件來減少AOF文件的體積。BGREWRITEAOF命令和BGSAVE建立快照原理十分類似,因此AOF文件重寫也須要用到子進程,這樣會致使性能問題和內存佔用問題,和快照持久化同樣。更糟糕的是,若是不加以控制的話,AOF文件的體積可能會比快照文件大好幾倍。

AOF重寫能夠產生一個新的AOF文件,這個新的AOF文件和原有的AOF文件所保存的數據庫狀態同樣,但體積更小。

AOF重寫是一個有歧義的名字,該功能是經過讀取數據庫中的鍵值對來實現的,程序無須對現有AOF文件進行任何讀入、分析或者寫入操做。

在執行 BGREWRITEAOF 命令時,Redis 服務器會維護一個 AOF 重寫緩衝區,該緩衝區會在子進程建立新AOF文件期間,記錄服務器執行的全部寫命令。當子進程完成建立新AOF文件的工做以後,服務器會將重寫緩衝區中的全部內容追加到新AOF文件的末尾,使得新舊兩個AOF文件所保存的數據庫狀態一致。最後,服務器用新的AOF文件替換舊的AOF文件,以此來完成AOF文件重寫操做

AOF持久化配置:

auto-aof-rewrite-percentage 100  
auto-aof-rewrite-min-size 64mb

假設用戶對Redis設置了以下配置選項而且啓用了AOF持久化。那麼當AOF文件體積大於64mb,而且AOF的體積比上一次重寫以後的體積大了至少一倍(100%)的時候,Redis將執行BGREWRITEAOF命令。

優勢

  • 最安全,在啓用appendfsync always時,任何已寫入的數據都不會丟失,使用在啓用appendfsync everysec也至多隻會丟失1秒的數據。

  • 因爲該機制對日誌文件的寫入操做採用的是append模式,所以在寫入過程當中即便出現宕機現象,也不會破壞日誌文件中已經存在的內容,即便出現了某條日誌只寫入了一半的狀況,也可使用redis-check-aof工具輕鬆修復。

  • AOF文件易讀,可修改,在進行了某些錯誤的數據清除操做後,只要AOF文件沒有rewrite,就能夠把AOF文件備份出來,把錯誤的命令刪除,而後恢復數據。

缺點

  • AOF文件一般比RDB文件更大

  • 性能消耗比RDB高

  • 數據恢復速度比RDB慢

Redis 4.0 對於持久化機制的優化

Redis 4.0 開始支持 RDB 和 AOF 的混合持久化(默認關閉,能夠經過配置項 aof-use-rdb-preamble 開啓)。

若是把混合持久化打開,AOF 重寫的時候就直接把 RDB 的內容寫到 AOF 文件開頭。這樣作的好處是能夠結合 RDB 和 AOF 的優勢, 快速加載同時避免丟失過多的數據。固然缺點也是有的, AOF 裏面的 RDB 部分是壓縮格式再也不是 AOF 格式,可讀性較差。

RDB和AOF到底該如何選擇?

1.不要僅僅使用 RDB,由於那樣會致使你丟失不少數據,由於RDB是隔一段時間來備份數據

2.也不要僅僅使用 AOF,由於那樣有兩個問題,第一,經過 AOF 作冷備沒有RDB恢復速度快; 第二,RDB 每次簡單粗暴生成數據快照,更加健壯,能夠避免 AOF 這種複雜的備份和恢復機制的 bug

3.用RDB恢復內存狀態會丟失不少數據,重放AOF日誌又很慢。Redis4.0推出了混合持久化來解決這個問題。將 rdb 文件的內容和增量的 AOF 日誌文件存在一塊兒。這裏的 AOF 日誌再也不是全量的日誌,而是自持久化開始到持久化結束的這段時間發生的增量 AOF 日誌,一般這部分 AOF 日誌很小。因而在 Redis 重啓的時候,能夠先加載 rdb 的內容,而後再重放增量 AOF 日誌就能夠徹底替代以前的 AOF 全量文件重放,重啓效率所以大幅獲得提高。

不管是AOF持久化仍是快照持久化,將數據持久化到硬盤上都是很是有必要的,但除了進行持久化外,用戶還必須對持久化獲得的文件進行備份(最好是備份到不一樣的地方),這樣才能儘可能避免數據丟失事故發生。若是條件容許的話,最好能將快照文件和從新重寫的AOF文件備份到不一樣的服務器上面。

隨着負載量的上升,或者數據的完整性變得愈來愈重要時,用戶可能須要使用到複製特性。

相關文章
相關標籤/搜索