Redis設計與實現 第 10 章 RDB 持久化
第 10 章 RDB 持久化
資料庫狀態:伺服器中的非空資料庫以及它們的鍵值對統稱為資料庫狀態
Redis 提供 RDB 持久化功能,將記憶體中的資料庫狀態儲存到磁碟中,避免資料意外丟失
RDB 檔案是一個經過壓縮的二進位制檔案,還可以通過該檔案還原生成 RDB 檔案時的資料庫狀態
10.1 RDB 檔案的建立與載入
SAVE、BGSAVE命令生成 RDB 檔案
SAVE 命令會阻塞 Redis 伺服器程序,直到檔案建立完畢,阻塞期間無法處理任何請求
BGSAVE 命令會派生子程序,由子程序負責建立 RDB 檔案,伺服器父程序繼續處理命令請求
建立 RDB 檔案的實際工作由 rdb.c/rdbSave 完成,兩個命令會以不同的方式呼叫此函式
RDB 檔案的載入工作在伺服器啟動時自動執行的,只要檢測到 RDB 檔案存在,自動載入 RDB 檔案
AOF檔案更新頻率通常比 RDB 檔案的更新頻率高,所以:
- 如果伺服器開啟了 AOF 持久化功能,伺服器會優先使用 AOF 檔案來還原資料庫狀態
- 只有在 AOF 持久化功能關閉才會使用 RDB 檔案來還原狀態
10.1.1 SAVE 命令執行時的伺服器狀態
阻塞,只有命令執行完成後客戶端的命令才會被處理
10.1.2 BGSAVE 命令執行時的伺服器狀態
伺服器可以繼續處理命令請求,但有些區別
- SAVE 命令被拒絕
- BGSAVE 命令也被拒絕
- BGREWRITEAOF 不能同時執行
- BGSAVE 在執行,被延遲到前者完成後
- 正在執行,BGSAVE 被拒絕
- 效能方面考慮,兩個子程序同時執行大量寫入操作
10.1.3 RDB 檔案載入時伺服器的狀態
阻塞
10.2 自動間隔性儲存
設定伺服器配置 save 選項,讓伺服器妹隔一段時間自動執行一次BGSAVE 選項
save 900 1
save 300 10
save 60 10000
在 900 s 內,對資料庫進行了至少一次修改
同理
三個條件滿足一個,BGSAVE 命令就會執行
10.2.1 設定儲存條件
save 900 1
save 300 10
save 60 10000
以上為預設設定,如果沒有指定配置引數或者傳入啟動引數方式
伺服器會根據 save 選項設定 redisServer.saveparams 屬性
預設情況如下:
10.2.2 dirty 計數器和 lastsave 屬性
- dirty計數器
- 記錄距離上一次執行 SAVE 命令或者 BGSAVE 命令之後伺服器對資料庫進行了多少次修改
- lastsave
- UNIX 時間戳
- 記錄了伺服器上一次成功執行 SAVE 命令或 BGSAVE 命令的時間
- UNIX 時間戳
伺服器成功執行一次資料庫修改命令之後就對 dirty 計數器進行更新
10.2.3 檢查儲存條件是否滿足
serverCron 預設每隔 100 ms 執行一次,對執行的伺服器維護,其中一項工作就是檢查設定的儲存條件是否滿足,是則執行 BGSAVE 命令
10.3 RDB 檔案結構
完整的 RDB 檔案結構如下:
常量:全大寫單詞
變數和資料:全小寫單詞
- REDIS:5 位元組,儲存 “REDIS” 5 個字元,方便程式快速分辨為 RDB 檔案
RDB 為二進位制資料,“REDIS” 儲存的不是 c 字串
-
db_version:4 位元組,為字串表示的常數, REB 版本號
-
database
-
零個或多個數據庫,以及資料庫中的鍵值對資料
-
如果資料庫狀態為空,此處也為空,長度 0 位元組
-
資料庫狀態非空,根據情況不同,長度不同
-
-
EOF:常量,1 位元組,標誌 RDB 檔案正文內容結束,即所有資料庫所有鍵值對載入完成
-
check_num:8 位元組無符號整數,校驗和,通過前四個部分計算而來,載入時計算是否與之相同驗證檔案是否損壞
10.3.1 database 部分
database 可以儲存任意多個非空資料庫
假設 0 號、3 號資料庫非空, RDB 檔案如圖,database 代表 0 號資料庫中的所有鍵值對
database 0 又可以再細分
-
SELECTDB:1 位元組,表明接下來讀入的是資料庫號碼
-
db_number:資料庫號碼,可以為1 3 5 位元組
-
key_value_pairs:資料庫中的所有鍵值對資料,如果有過期時間也會儲存在一起
10.3.2 key_value_pairs 部分
不帶過期時間的鍵值對
TYPE | KEY | VALUE |
---|
- TYPE:1 位元組
- value:字串物件,同上襦的 String 型別
帶過期時間的鍵值對
EXPIRETIME_MS | MS | TYPE | KEY | VALUE |
---|
- EXPIRETIME_MS:1 位元組,告知程式即將讀入的是毫秒為單位的過期時間
- ms:8 位元組的帶符號整數,毫秒為單位為 UNIX 時間戳
10.3.3 value 編碼
1.字串物件:REDIS_RDB_TYPE_STRING
value 儲存的為字串物件,編碼有 REDIS_ENCODING_INT 或者 REDIS_ENCODING_RAW
-
REDIS_ENCODING_INT
-
長度不超過 32 位的整數
-
ENCODING 可以是 REDIS_RDB_ENC_INT8、REDIS_RDB_ENC_INT16、REDIS_RDB_ENC_INT32 代表使用幾位來儲存整數值 integer
-
-
REDIS_ENCODING_RAW
-
字串物件
-
壓縮與不壓縮儲存
-
小於等於 20 位元組,原樣儲存
-
大於 20 位元組,壓縮之後再儲存
-
在伺服器開啟 RDB 檔案壓縮功能進行的
-
否則總是無壓縮儲存
-
-
無壓縮
-
壓縮
- REDIS_RDB_ENC_LZF:常量,表示字串被 LZF 演算法壓縮了,程式會對後面三個欄位使用解壓縮
- compressed_len:壓縮之後的長度
- origin_len:壓縮之前的長度
- compressed_string:壓縮之後的字串
-
2.列表物件:REDIS_RDB_TYPE_LIST
value 儲存的是 REDIS_ENCODING_LINKEDLIST 編碼的列表物件
-
list_length:列表長度,列表儲存了多少個項
-
item:列表的列表項,每個列表項都是字串物件
- 包含長度與實際值
3.集合物件:REDIS_RDB_TYPE_SET
REDIS_ENCODING_HT
-
set_size:集合大小
-
elem:字串物件
- 包含長度與實際值
4.雜湊表物件:REDIS_RDB_TYPE_HASH
REDIS_ENCODING_HT
鍵與值相鄰排列
5.有序集合物件:REDIS_RDB_TYPE_ZSET
REDIS_ENCODING_SKIPLIST
成員與分值緊挨,分值為 double 浮點數,在 double、字串中互相轉換
6.INTSET 編碼集合:REDIS_RDB_TYPE_INTSET
整數集合與字串互相轉換
7.ZIPLIST 編碼的列表、雜湊表或者有序集合
REDIS_RDB_TYPE_LIST_ZIPLIST
REDIS_RDB_TYPE_HASH_ZIPLIST
REDIS_RDB_TYPE_ZSET_ZIPLIST
壓縮列表
-
壓縮列表轉換字串
-
字串儲存到 RDB
-
字串轉換壓縮列表
-
根據 TYPE 設定型別
- REDIS_RDB_TYPE_LIST_ZIPLIST:列表
- REDIS_RDB_TYPE_HASH_ZIPLIST:雜湊表
- REDIS_RDB_TYPE_ZSET_ZIPLIST:有序集合