1. 程式人生 > >Redis 的持久化機制

Redis 的持久化機制

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 後的記憶體資料圖:

圖1

圖1

總結:

1. 根據業務需要選擇合適的資料型別,併為不同的應用場景設定相應的緊湊儲存引數。

2. 當業務場景不需要資料持久化時,關閉所有的持久化方式可以獲得最佳的效能以及最大的記憶體使用量。

3. 如果需要使用持久化,根據是否可以容忍重啟丟失部分資料在快照方式與語句追加方式之間選擇其一,不要使用虛擬記憶體以及 diskstore 方式。

4. 不要讓你的 Redis 所在機器實體記憶體使用超過實際記憶體總量的3/5。

好了 完了 。。。。。。。。。。。。