標籤:

圖解Redis之持久化篇

持久化

Redis是典型的key-value型資料庫,我們通常把伺服器的非空資料庫及鍵值對統稱為資料庫狀態

因為Redis是內存資料庫,它把自己的資料庫狀態存儲在內存中,所以一旦發生停電或者其他因素使主機宕機,那麼數據將會丟失,所以Redis引入了持久化操作,它把Redis在內存中的資料庫狀態持久化到硬碟,當伺服器重新啟動的時候,去載入硬碟中的持久化文件就可恢復現場狀態.

Redis有兩種持久化方式:RDB持久化和AOF持久化,前者是通過把資料庫狀態的鍵值對保存起來,而AOF則是把命令保存起來,那麼伺服器是使用哪種持久化呢?因為AOF文件更新頻率更高,所以優先AOF.接下來將分別介紹兩種持久化方式

RDB持久化

  • 創建RDB文件:

伺服器可以通過save和bgsave來實現rdb持久化,前者會阻塞伺服器進程,導致在進行save操作期間,伺服器無法繼續處理客戶端請求;bgsave則會派生一個子進程,讓子進程去進行持久化操作,而伺服器進程繼續響應客戶端.這裡要說明的是bgsave和save這兩個操作無法同時進行,因為會出現競爭條件.

  • 持久化策略

知道如何創建RDB文件後,我們討論何時執行save和bgsave持久化操作?

由於bgsave會創建子進程來進行持久化操作,並不阻礙伺服器進程處理其他事,所以我們可以讓伺服器每隔一段時間執行一次bgsave,因此可以通過設置保存條件來讓伺服器執行bgsave操作.

struct redisServer{ //... struct saveparam *saveparam;//記錄了保存條件的數組 sds aof_buf //AOF緩衝區,用來存放寫命令的協議請求內容 //...};//條件:當滿足條件(在time_t秒內,修改次數達到changes)時,伺服器執行bgsavestruct saveparam{ time_t seconds;//秒數 int changes//修改數};

好,現在我們真正講述Redis是如何檢查保存條件滿足與否!

Redis伺服器有個周期性函數serverCron,默認每隔100ms執行一次,Redis就是通過它來檢測保存條件

介紹到這裡,我們我們已經知道RDB持久化操作的時機和方式,接下來一起看看RDB的文件結構.

  • REDIS長度5位元組,保存著R E D I S 五個字元,可用來判斷文件是否是rdb文件

  • db_version長度為4位元組,值為整數型字元串,代表rdb文件的版本號.比如0006
  • databases 資料庫狀態,包含一個或多個資料庫,以及各個資料庫中的鍵值對
  • EOF常量,1位元組,標誌著rdb文件的結束
  • check_sum:8位元組的校驗和,程序通過對REDIS,db_version,databases,EOF四部分計算得來,伺服器載入rdb文件時,會將文件計算得來的校驗和與該值對比,依次來檢測rdb文件正確性.

知道它的結構後,我們具體看看是如何保存的:

  • databases

有幾個非空資料庫則保存幾個,每個非空資料庫又包含SELECTDB db_number key_value_pairs,

SELECTDB常用為1位元組,當程序讀到這個值時,知道自己要選擇資料庫,db_number資料庫號,

key_value_pairs為當前資料庫中所有的鍵值對

  • key_value_pairs:

    • Type有以下幾種類型

REDIS_RDB_TYPE_STRING REDIS_RDB_TYPE_LIST REDIS_RDB_TYPE_LIST_ZIPLISTREDIS_RDB_TYPE_SET REDIS_RDB_TYPE_SET_INTSETREDIS_RDB_TYPE_ZSET REDIS_RDB_TYPE_ZSET_ZIPLIST REDIS_RDB_TYPE_HASH REDIS_RDB_TYPE_HASH_ZIPLIST

key總是字元串類型,鍵值對的形式與鍵是否帶過期值有關,詳情參考上圖,接下來一起學習value

  • value的編碼
  • 字元串對象:字元串對象的格式主要分為兩種,一種是原樣,一種是壓縮後的,int型字元串原樣輸出,raw編碼的如果長度大於20byte採取壓縮形式,否則和int型相同.分別如下所示

  • 列表對象

  • 集合對象(同列表)

  • 集合對象:同集合,不過是元素項開頭加了一個score

  • 哈希表對象:依次table_size key1 value1 key2 value2
  • INTSET 整數集合
  • ziplist編碼的列表,哈希表或有序集合

到這裡RDF持久化基本描述完畢(對rdb文件分析感興趣的可以自己看),接下來一起學習AOF

AOF持久化

與RDB持久化保存資料庫中的鍵值對來記錄資料庫不同,AOF持久化是通過記錄Redis伺服器所執行的寫命令來記錄資料庫狀態的.那麼AOF持久化具體怎麼實現的呢?

AOF持久化的功能實現可描述為命令追加(append),文件寫入,文件同步(sync)三個步驟

  • 命令追加:伺服器每執行一次寫命令,就把對應的命令請求協議內容添加到aof_buf緩衝區

  • 文件寫入和文件同步

AOF文件的載入與數據還原

AOF重寫

由於AOF文件更行頻率很高,用戶會有大量的寫命令,如果每次都記錄,則會浪費大量空間,所以Redis實現了AOF重寫功能:首先從資料庫中讀取鍵現在的值,然後用一條命令去記錄鍵值對,代替之前記錄這個鍵值對的多條命令

AOF後台重寫

由於redis會伴隨大量的寫入操作,如果伺服器去執行aof重寫,則可能長時間阻塞,於是伺服器使用子進程來進行aof重寫,子進程持有伺服器進程的數據副本.然而在子進程每次重寫期間,伺服器又會有新的寫請求,那麼如何解決這個數據不一致問題呢?

為了解決這個問題,Redis伺服器設置了一個aof重寫緩衝區,在創建了子進程時,開始使用緩衝區,在子進程重寫期間,每當Redis伺服器有新的寫操作,都會把命令同時發給aof緩衝區和重寫緩衝區,這樣一來

  • AOF緩衝區的內容會定期被寫人和同步到AOF文件,對現有AOF文件的處理工作如常進行。
  • 從創建子進程開始,伺服器執行的所有寫命令都會被記錄到AOF重寫緩衝區裡面.

當子進程完成AOF重寫工作之後,它會向父進程發送一個信號,父進程在接到該信號後:

  1. 將AOF重寫緩衝區中的所有內容寫入到新AOF文件中,這時新AOF文件所保存的資料庫狀態將和伺服器當前的資料庫狀態一致。

  2. 對新的AOF文件進行改名,原子地(atomic)覆蓋現有的AOF文件,完成新舊兩個AOF文件的替換。

推薦閱讀:

Spring Boot使用Redis進行消息的發布訂閱
No-SQL資料庫中的事務性設計
Redis源碼剖析--內存分配
redis使用消息隊列的場合?

TAG:Redis |