1. 程式人生 > 其它 >Redis學習詳解(一):Redis持久化機制之RDB

Redis學習詳解(一):Redis持久化機制之RDB

Redis的持久化機制有兩種:RDB持久化和AOF持久化。因為Redis是一個記憶體資料庫,如果沒有合適的持久化機制,那麼一旦伺服器程序退出,伺服器中的資料庫狀態也會消失。本章介紹RDB持久化機制。

RDB持久化

RDB持久化,是Redis可以將資料庫狀態儲存到一個RDB檔案中,並可以通過該RDB檔案生成RDB檔案的時候的資料庫狀態。RDB檔案是一個經過壓縮的二進位制檔案。

生成RDB檔案的Redis命令有兩個:

  1. SAVE
  2. BGSAVE

SAVE命令會阻塞Redis伺服器,此期間伺服器不能處理任何命令請求;
BGSAVE命令是派生(fork)出一個子程序,然後子程序負責建立RDB檔案,伺服器繼續處理命令請求;

BGSAVE命令執行的伺服器狀態

BGSAVE期間,伺服器處理SAVE、BGSAVE、BGREWRIREAOF三個命令的方式與平時不同。

BGSAVE期間,伺服器會直接拒絕客戶端傳送的SAVE命令,伺服器禁止SAVE命令與BGSAVE命令同時進行是為了避免伺服器程序和子程序同時執行兩個rdbSave呼叫產生競爭條件。
同理,BGSAVE期間的BGSAVE命令也會直接拒絕。

BGREWRITEAOF和BGSAVE兩個命令不能同時執行:

  • 如果BGSAVE命令正在執行,客戶端傳送的BGREWRITEAOF命令會被延遲到BGSAVE命令執行完畢之後執行;
  • 如果BGREWRITEAOF命令正在執行,那麼客戶端傳送的BGSAVE命令會被伺服器拒絕;

BGREWRITEAOF和BGSAVE不能同時使用主要是處於效能的考慮,因為兩個命令都需要執行大量的磁碟寫入操作。

自動間隔性儲存

在Redis中,使用者可以通過save選項設定多個儲存條件,只要其中任意一個條件滿足,伺服器便執行BGSAVE命令
save 900 1
save 間隔時間(單位為秒) 修改次數

在原始碼底層的體現是,所有的save選項條件是通過一個saveparam結構儲存的。

點選檢視程式碼
struct saveparam {
  time_t seconds;
  int changes;
};

伺服器狀態維持了一個dirty計數器和lastsave屬性,dirty計數器記錄了距離上一次成功執行SAVE命令或者BGSAVE命令之後伺服器對資料庫狀態進行修改的次數。lastsave是一個UNIX時間戳,記錄了伺服器上一次成功執行SAVE命令或者BGSAVE命令的時間。
然後Redis有一個伺服器周期函式,用來週期檢查是否滿足save條件,如果滿足則進行BGSAVE。
以上便是Redis自動進行間隔性資料儲存的原理。

RDB檔案結構

RDB檔案分為五個部分:REDIS、db_version、databases、EOF、check_sum。

REDIS

REDIS部分的作用:標識該檔案是一個RDB檔案。
儲存著“REDIS”五個字元。

db_version

db_version部分的作用:標識RDB檔案的版本號。

databases

databases部分的作用:儲存資料庫資訊。

databases部分包含零個或任意多個數據庫,以及各個資料庫的鍵值對。
若伺服器的資料庫狀態為空,那麼該部分也為空。否則儲存各個資料庫的資訊。

每一個非空資料庫在RDB檔案中可以儲存為SELECTDB、db_number、key_value_pairs三個部分。

SELECTDB長度為1位元組,表示接下來讀入的會是一個數據庫號碼。
db_number儲存著一個數據庫號碼,根據號碼不同,伺服器使用SELECT命令進行資料庫切換。
key_value_pairs部分儲存資料庫中所有鍵值對資料,包括如果有過期時間便帶有過期時間。

key_value_pairs

key_value_pairs分為三個部分:TYPE,key,value。

TYPE記錄的是value的型別,有以下幾種常量:

  1. REDIS_RDB_TYPE_STRING
  2. REDIS_RDB_TYPE_LIST
  3. REDIS_RDB_TYPE_SET
  4. REDIS_RDB_TYPE_ZSET
  5. REDIS_RDB_TYPE_HASH
  6. REDIS_RDB_TYPE_LIST_ZIPLIST
  7. REDIS_RDB_TYPE_SET_INTSET
  8. REDIS_RDB_TYPE_ZSET_ZIPLIST
  9. REDIS_RDB_TYPE_HASH_ZIPLIST

帶有過期時間的鍵值則在三個部分的前面在加上兩個部分:EXPIRETIME_MS,ms。
前面的為標記是存在過期時間的,後面的為過期時間。

value的編碼

value的編碼中的編碼與Redis底層資料型別有關,這裡我們先寫value的編碼。

字串物件

字串物件是TYPE為REDIS_RDB_TYPE_STRING的物件。
字串物件存在可以儲存INT值的編碼,如果為此種編碼,那麼在檔案中的儲存便是先儲存編碼,再儲存值。
ENCODING | integer

字串物件如果是儲存字串的編碼,有壓縮和不壓縮兩種方法儲存字串。
若字串長度小於20位元組,那麼便會原樣儲存;若字串長讀大於20位元組,那麼便壓縮之後再儲存。

如果是無壓縮的字串,儲存在RDB檔案中便是先儲存字串長度,再儲存值。
len | string

如果是壓縮的字串,那麼儲存在RDB中的格式如下:
REDIS_RDB_ENC_LZF(標識已被LZF演算法壓縮) | compressed_len(壓縮後長度) | origin_len(字串原長度) | compressed_string(壓縮之後的字串)

列表物件

列表物件的RDB檔案儲存格式如下:
list_length(列表長度) | item1 | item2 | itemN

集合物件

與列表物件型別,只是TYPE會不同。
set_size(列表長度) | elem1 | elem2 | elemN

雜湊表物件

雜湊表的RDB檔案儲存格式如下:
hash_size|key_value_pair1|……

有序集合物件

與集合物件只是TYPE不同。

INTSET物件

TYPE為REDIS_RDB_TYPE_SET_INTSET,然後將其轉換為字串物件。讀取RDB檔案時候,會將字串物件轉換為原來的INTSET物件。

ZIPLIST編碼的列表、雜湊表或者有序集合

value為一個壓縮列表物件,讀取時只是根據TYPE不同進行逆過程。

總結

RDB是Redis兩種持久化方法之一。
RDB優點:

  1. 生成多個數據檔案,每一個數據檔案代表某一個時刻的redis的資料,適合冷備份。
  2. RDB對redis對外提供讀寫服務影響小,可以讓redis保持高效能。
  3. 相較於AOF持久化機制而言更快。

RDB缺點:

  1. RDB是一個自動間隔性儲存的機制,所以丟失資料量可能會比AOF多。
  2. 如果RDB檔案過大,會導致對客戶端提供的服務暫停一段時間。