Redis-技術專區-幫從底層徹底吃透RDB技術原理

李浩宇Alex發表於2021-09-03

每日一句

低頭是一種能力,它不是自卑,也不是怯弱,它是清醒中的嬗變。有時,稍微低一下頭,或者我們的人生路會更精彩。

前提概要

Redis是一個的鍵-值(K-V)對的記憶體資料庫服務,通常包含了任意個非空資料庫。而每個非空的鍵值資料庫中又可以存放任意個K-V,基本的結構如下圖所示:

image

  • Redis的強勁效能很大程度上是由於其將所有資料都儲存在了記憶體中,為了使Redis在重啟之後仍能保證資料不丟失,需要將資料從記憶體中以某種形式同步到硬碟中,這一過程就是持久化。

  • 我們知道redis中快取的資料都存放在記憶體中,一旦服務故障,會導致記憶體中資料丟失,所以需要一種資料持久化的方案,將redis記憶體中的資料,寫入磁碟,當redis重啟後,能從磁碟中恢復資料。

Redis伺服器的結構

  • 這裡有一個問題,因為Redis是一個記憶體資料庫,如果它直接將資料儲存到記憶體中,但是如果不考慮將儲存在記憶體中的資料持久化到硬碟裡面,一旦伺服器程式退出,那麼資料庫中的資料也會消失。

  • 資料庫的持久化機制主要有兩種,一種是RDB機制,另外一種是AOF機制,AOF機制已經在前面的文章中介紹過了,

  • 如果有興趣可以去看看,而本文主要講述RDB機制。

RDB持久化方式

RDB持久化是指在指定的時間間隔內將redis記憶體中的資料集快照寫入磁碟,實現原理是redis服務在指定的時間間隔內先fork一個子程式,由子程式將資料集寫入臨時檔案,寫入成功後,再替換之前的檔案,用二進位制壓縮儲存,生成dump.rdb檔案存放在磁碟中。

image

RDB機制

  • Redis提供了RDB持久化能力,這個功能可以將Redis在記憶體中的資料庫狀態保持在磁碟裡面,避免資料意外丟失。

  • RDB持久化機制可以手動執行,也可以根據伺服器配置選定定期執行操作,該功能可以將某一個時間點的資料快照進行儲存到一個RDB檔案中。

RDB優勢

  • 一旦採用該方式,那麼你的整個Redis資料庫將只包含一個檔案,這對於檔案備份而言是非常完美的。比如,你可能打算每個小時歸檔一次最近24小時的資料,同時還要每天歸檔一次最近30天的資料。通過這樣的備份策略,一旦系統出現災難性故障,我們可以非常容易的進行恢復。

  • 對於災難恢復而言,RDB是非常不錯的選擇。因為我們可以非常輕鬆的將一個單獨的檔案壓縮後再轉移到其它儲存介質上。

  • 效能最大化。對於Redis的服務程式而言,在開始持久化時,它唯一需要做的只是fork出子程式,之後再由子程式完成這些持久化的工作,這樣就可以極大的避免服務程式執行IO操作了。

  • 相比於AOF機制,如果資料集很大,RDB的啟動效率會更高。

RDB劣勢

  • 如果你想保證資料的高可用性,即最大限度的避免資料丟失,那麼RDB將不是一個很好的選擇。因為系統一旦在定時持久化之前出現當機現象,此前沒有來得及寫入磁碟的資料都將丟失。

  • 由於RDB是通過fork子程式來協助完成資料持久化工作的,因此,如果當資料集較大時,可能會導致整個伺服器停止服務幾百毫秒,甚至是1秒鐘。

RDB配置規則

在redis的6379.conf配置檔案中:

備份配置引數

save <seconds> <changes>

save <指定時間間隔> <執行指定次數更新操作>,滿足條件就將記憶體中的資料同步到硬碟中。官方出廠配置預設是 900秒內有1個更改,300秒內有10個更改以及60秒內有10000個更改,則將記憶體中的資料快照寫入磁碟。

save 900 1      #在900秒(15分鐘)之後,如果至少有一個key發生變化,則dump記憶體快照
save 300 10     #在300秒(15分鐘)之後,如果至少有10個key發生變化,則dump記憶體快照
save 60 10000   #在60秒(1分鐘)之後,如果至少有10000個key發生變化,則dump記憶體快照

檔案配置引數

預設的rdb檔案路徑是當前目錄,檔名是dump.rdb,可以在配置檔案中修改路徑和檔名,分別是dir和dbfilename.

# 存放快照的目錄
dir ./ # rdb檔案儲存路徑
dbfilename dump.rdb # rdb檔名

壓縮配置引數

在進行映象備份時,是否進行壓縮。

rdbcompression yes  #Redis預設是開啟壓縮的。
# yes:壓縮,但是需要一些cpu的消耗。
# no:不壓縮,需要更多的磁碟空間。

如果沒有觸發自動快照,需要對Redis執行手動快照操作,save和bgsave命令來手動快照,兩個命令是:

  • SAVE:由主程式進行快照,會阻塞其他請求。
  • BGSAVE:通過fork子程式進行快照,不會阻塞其他請求。

注意:由於Redis使用fork來複制一份當前程式,那麼子程式就會佔有和主程式一樣的記憶體資源,比如說主程式8G記憶體,那麼在備份的時候,必須保證有16G的記憶體,要不然會啟用虛擬記憶體,效能非常的差。

快照的過程如下:

  1. Redis使用fork函式複製一份當前程式(父程式)的副本(子程式);
  2. 父程式繼續接收並處理客戶端發來的命令,而子程式開始將記憶體中的資料寫入硬碟中的臨時檔案;
  3. 當子程式寫入完所有資料後會用該臨時檔案替換舊的RDB檔案,至此一次快照操作完成。(注意:會存在寫一部命令壓縮快取區,記錄寫入rdb檔案時候的操作)

在執行fork的時候作業系統會使用寫時複製(copy-on-write)策略,即fork函式發生的一刻父子程式共享同一記憶體資料,當父程式要更改其中某片資料時(如執行一個寫命令),作業系統會將該片資料複製一份以保證子程式的資料不受影響,所以新的RDB檔案儲存的是執行fork時那一刻的記憶體快照資料。

通過上述過程可以發現Redis在進行快照的過程中不會修改RDB檔案,只有快照結束後才會將舊的檔案替換成新的,也就是說任何時候RDB檔案都是完整的。這使得可以通過定時備份RDB檔案來實現Redis資料庫備份。

快照的過程壓縮分析:

RDB檔案是經過壓縮(上文介紹了:可以配置rdbcompression引數以禁用壓縮節省CPU佔用)的二進位制格式,所以佔用的空間會小於記憶體中的資料大小,更加利於傳輸。

快照的讀取載入過程:
  • Redis啟動後會讀取RDB快照檔案,將資料從硬碟載入到記憶體。根據資料量大小與結構和伺服器效能不同,這個時間也不同。通常將一個記錄一千萬個字串型別鍵、大小為1GB的快照檔案載入到記憶體中需要花費20~30秒鐘

  • 通過RDB方式實現持久化,一旦Redis異常退出,就會丟失最後一次快照以後更改的所有資料。這就需要開發者根據具體的應用場合,通過組合設定自動快照條件的方式來將可能發生的資料損失控制在能夠接受的範圍。如果資料很重要以至於無法承受任何損失,則可以考慮使用AOF方式進行持久化。

RDB 的優缺點

優點:

  1. 適合大規模的資料恢復。
  2. 如果業務對資料完整性和一致性要求不高,RDB是很好的選擇。

缺點:

  1. 資料的完整性和一致性不高,因為RDB可能在最後一次備份時當機了。
  2. 備份時佔用記憶體,因為Redis 在備份時會獨立建立一個子程式,將資料寫入到一個臨時檔案(此時記憶體中的資料是原來的兩倍),最後再將臨時檔案替換之前的備份檔案。
  3. 由於RDB是通過fork子程式來協助完成資料持久化工作的,因此,如果當資料集較大時,可能會導致整個伺服器停止服務幾百毫秒,甚至是1秒鐘。(回寫和覆蓋的時候用的是主程式)。

RDB與AOF二者選擇的標準(雖然還沒有講AOF,提前普及)

  • 如果系統是願意犧牲一些效能,換取更高的快取一致性(aof)

  • 或者是願意寫操作頻繁的時候,不啟用備份來換取更高的效能,待手動執行save的時候,再做備份(rdb)。

Redis允許同時開啟AOF和RDB,既保證了資料安全又使得進行備份等操作十分容易。此時重新啟動Redis後Redis會使用AOF檔案來恢復資料,因為AOF方式的持久化可能丟失的資料更少。

總結

  • Redis 預設開啟RDB持久化方式,在指定的時間間隔內,執行指定次數的寫操作,則將記憶體中的資料寫入到磁碟中。

  • RDB 持久化適合大規模的資料恢復但它的資料一致性和完整性較差。

  • Redis 需要手動開啟AOF持久化方式,預設是每秒將寫操作日誌追加到AOF檔案中。

所以Redis的持久化和資料的恢復要選擇在夜深人靜的時候執行是比較合理的。

相關文章