1. 程式人生 > >redis的持久化方式

redis的持久化方式

應用程序 參數設置 了解 log 技術 不常用 一個 技術分享 條件

非常感謝《redis實戰》真本書,本文大多內容也參考了書中的內容。非常推薦大家看一下《redis實戰》這本書,感覺書中的很多理論性東西還是很不錯的。

為什麽本文的名字要加上春夏秋冬又一春,哈哈 ,這是一部韓國的電影,我感覺電影不錯,所以就用在文章名字上了,沒有什麽特別的含義,然後下面的有些配圖也是電影相關鏡頭。

技術分享圖片

很多時候我們需要持久化數據也就是將內存中的數據寫入到硬盤裏面,大部分原因是為了之後重用數據(比如重啟機器、機器故障之後回復數據),或者是為了防止系統故障而將數據備份到一個遠程位置。

Redis不同於Memcached的很重一點就是,Redis支持持久化,而且支持兩種不同的持久化操作。Redis的一種持久化方式叫快照(snapshotting,RDB)

,另一種方式是只追加文件(append-only file,AOF).這兩種方法各有千秋,下面我會詳細這兩種持久化方法是什麽,怎麽用,如何選擇適合自己的持久化方法。

快照(snapshotting)持久化

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持久化。

AOF(append-only file)持久化

與快照持久化相比,AOF持久化 的實時性更好,因此已成為主流的持久化方案。默認情況下Redis沒有開啟AOF(append only file)方式的持久化,可以通過appendonly參數開啟:

appendonly yes

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

技術分享圖片

在Redis的配置文件中存在三種同步方式,它們分別是:


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

AOF雖然在某個角度可以將數據丟失降低到最小而且對性能影響也很小,但是極端的情況下,體積不斷增大的AOF文件很可能會用完硬盤空間。另外,如果AOF體積過大,那麽還原操作執行時間就可能會非常長。

為了解決AOF體積過大的問題,用戶可以向Redis發送 BGREWRITEAOF命令 ,這個命令會通過移除AOF文件中的冗余命令來重寫(rewrite)AOF文件來減小AOF文件的體積。BGREWRITEAOF命令和BGSAVE創建快照原理十分相似,所以AOF文件重寫也需要用到子進程,這樣會導致性能問題和內存占用問題,和快照持久化一樣。更糟糕的是,如果不加以控制的話,AOF文件的體積可能會比快照文件大好幾倍。

文件重寫流程:

技術分享圖片 和快照持久化可以通過設置save選項來自動執行BGSAVE一樣,AOF持久化也可以通過設置

auto-aof-rewrite-percentage

選項和

auto-aof-rewrite-min-size

選項自動執行BGREWRITEAOF命令。舉例:假設用戶對Redis設置了如下配置選項並且啟用了AOF持久化。那麽當AOF文件體積大於64mb,並且AOF的體積比上一次重寫之後的體積大了至少一倍(100%)的時候,Redis將執行BGREWRITEAOF命令。

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

無論是AOF持久化還是快照持久化,將數據持久化到硬盤上都是非常有必要的,但除了進行持久化外,用戶還必須對持久化得到的文件進行備份(最好是備份到不同的地方),這樣才能盡量避免數據丟失事故發生。如果條件允許的話,最好能將快照文件和重新重寫的AOF文件備份到不同的服務器上面。

隨著負載量的上升,或者數據的完整性變得 越來越重要時,用戶可能需要使用到復制特性。

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

Redis 4.0 開始支持 RDB 和 AOF 的混合持久化(默認關閉,可以通過配置項 aof-use-rdb-preamble 開啟)。

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

參考:

《Redis實戰》

深入學習Redis(2):持久化

redis的持久化方式