Redis的持久化機制

jopen 9年前發布 | 16K 次閱讀 Redis NoSQL數據庫

原文</i>  http://itindex.net/detail/53029-redis </span>


Redis由于支持非常豐富的內存數據結構類型,如何把這些復雜的內存組織方式持久化到磁盤上是一個難題,所以Redis的持久化方式與傳統數據庫的方式有比較多的差別,Redis一共支持四種持久化方式,分別是:

  • 定時快照方式(snapshot)
  • 基于語句追加文件的方式(aof)
  • 虛擬內存(vm)
  • Diskstore方式

在設計思路上,前兩種是基于全部數據都在內存中,即小數據量下提供磁盤落地功能,而后兩種方式則是作者在嘗試存儲數據超過物理內存時,即大數據量 的數據存儲,截止到本文,后兩種持久化方式仍然是在實驗階段,并且vm方式基本已經被作者放棄,所以實際能在生產環境用的只有前兩種,換句話說Redis 目前還只能作為小數據量存儲(全部數據能夠加載在內存中),海量數據存儲方面并不是Redis所擅長的領域。下面分別介紹下這幾種持久化方式:

定時快照方式(snapshot):

該持久化方式實際是在Redis內部一個定時器事件,每隔固定時間去檢查當前數據發生的改變次數與時間是否滿足配置的持久化觸發的條件,如果滿足 則通過操作系統fork調用來創建出一個子進程,這個子進程默認會與父進程共享相同的地址空間,這時就可以通過子進程來遍歷整個內存來進行存儲操作,而主 進程則仍然可以提供服務,當有寫入時由操作系統按照內存頁(page)為單位來進行copy-on-write保證父子進程之間不會互相影響。

該持久化的主要缺點是定時快照只是代表一段時間內的內存映像,所以系統重啟會丟失上次快照與重啟之間所有的數據。

基于語句追加方式(aof):

aof方式實際類似mysql的基于語句的binlog方式,即每條會使Redis內存數據發生改變的命令都會追加到一個log文件中,也就是說這個log文件就是Redis的持久化數據。

aof的方式的主要缺點是追加log文件可能導致體積過大,當系統重啟恢復數據時如果是aof的方式則加載數據會非常慢,幾十G的數據可能需要幾 小時才能加載完,當然這個耗時并不是因為磁盤文件讀取速度慢,而是由于讀取的所有命令都要在內存中執行一遍。另外由于每條命令都要寫log,所以使用 aof的方式,Redis的讀寫性能也會有所下降。

虛擬內存方式:

虛擬內存方式是Redis來進行用戶空間的數據換入換出的一個策略,此種方式在實現的效果上比較差,主要問題是代碼復雜,重啟慢,復制慢等等,目前已經被作者放棄。

diskstore方式:

diskstore方式是作者放棄了虛擬內存方式后選擇的一種新的實現方式,也就是傳統的B-tree的方式,目前仍在實驗階段,后續是否可用我們可以拭目以待。

Redis持久化磁盤IO方式及其帶來的問題

有Redis線上運維經驗的人會發現Redis在物理內存使用比較多,但還沒有超過實際物理內存總容量時就會發生不穩定甚至崩潰的問題,有人認為 是基于快照方式持久化的fork系統調用造成內存占用加倍而導致的,這種觀點是不準確的,因為fork 調用的copy-on-write機制是基于操作系統頁這個單位的,也就是只有有寫入的臟頁會被復制,但是一般你的系統不會在短時間內所有的頁都發生了寫 入而導致復制,那么是什么原因導致Redis崩潰的呢?

答案是Redis的持久化使用了Buffer IO造成的,所謂Buffer IO是指Redis對持久化文件的寫入和讀取操作都會使用物理內存的Page Cache,而大多數數據庫系統會使用Direct IO來繞過這層Page Cache并自行維護一個數據的Cache,而當Redis的持久化文件過大(尤其是快照文件),并對其進行讀寫時,磁盤文件中的數據都會被加載到物理內 存中作為操作系統對該文件的一層Cache,而這層Cache的數據與Redis內存中管理的數據實際是重復存儲的,雖然內核在物理內存緊張時會做 Page Cache的剔除工作,但內核很可能認為某塊Page Cache更重要,而讓你的進程開始Swap ,這時你的系統就會開始出現不穩定或者崩潰了。我們的經驗是當你的Redis物理內存使用超過內存總容量的3/5時就會開始比較危險了。

下圖是Redis在讀取或者寫入快照文件dump.rdb后的內存數據圖:

Redis的持久化機制

總結:

  1. 根據業務需要選擇合適的數據類型,并為不同的應用場景設置相應的緊湊存儲參數。
  2. 當業務場景不需要數據持久化時,關閉所有的持久化方式可以獲得最佳的性能以及最大的內存使用量。
  3. 如果需要使用持久化,根據是否可以容忍重啟丟失部分數據在快照方式與語句追加方式之間選擇其一,不要使用虛擬內存以及diskstore方式。
  4. 不要讓你的Redis所在機器物理內存使用超過實際內存總量的3/5。
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!