春夏秋冬又一春之Redis持久化

SnailClimb發表於2019-01-19

歷史文章推薦:

一隻準程式猿的嘮叨

可能是最漂亮的Spring事務管理詳解

Java多執行緒學習(八)執行緒池與Executor 框架

面試中關於Redis的問題看這篇就夠了

非常感謝《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實戰》

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

歡迎關注我的微信公眾號:"Java面試通關手冊"(一個有溫度的微信公眾號,無廣告,單純技術分享,期待與你共同進步~~~堅持原創,分享美文,分享各種Java學習資源。)

最後,就是使用阿里雲伺服器一段時間後,感覺阿里雲真的很不錯,就申請做了阿里雲大使,然後這是我的優惠券地址.

二維碼

相關文章