Redis RDB格式

概覽

Header

RDB文件的頭部占用9bytes,前5bytes為Magic String,后4bytes為版本號;

52 45 44 49 53 #"REDIS",就像java的class文件以0xCAFEBABE開頭一樣
30 30 30 36    #RDB版本號,30表示‘0’,版本號為0006=6

注意:版本號是字符串而不是整型;:

 snprintf(magic,sizeof(magic),"REDIS%04d",RDB_VERSION);

Body

DB Selector

FE開頭表示后跟表示DB Selector;例如:

FE 00#FE表明數據庫的哪個db,此處為db0

注意:DB Selector長度不固定,具體的編碼方式請參見后文的Length編碼

AUX Fields

FA開頭表示后跟AUX Fields,記錄生成Dump文件的Redis相關信息,例如redis-ver、redis-bits、used-mem、aof-preamble和repl-id等;
這些信息采用String編碼


注意:redis3.0版本的RDB版本號為6,redis3.2的版本號為7;

Key-Value

key-value有三種格式:

  1. expire為second

    FD $unsigned int    #失效時間(秒),4個字節
    $value-type         #1個字節,表明數據類型:set,map等
    $string-encoded-key #key值,字符串類型
    $encoded-value      #value,編碼方式和類型有關
    
  2. expire為millisecond

    FC $unsigned long    #失效時間(毫秒),8個字節
    $value-type          #數據類型,1個字節
    $string-encoded-key  #key,字符串類型
    $encoded-value       #value,編碼方式和類型有關
    
  3. 無expire

    $value-type         #數據類型,1個字節
    $string-encoded-key #key,字符串類型
    $encoded-value      #value,編碼方式和類型有關
    

Footer

FF              #RDB文件的結束
8byte checksum #循環冗余校驗碼,Redis采用crc-64-jones算法,初始值為0

編碼算法說明

Length編碼

長度采用BigEndian格式存儲,為無符號整數

  1. 如果以"00"開頭,那么接下來的6個bit表示長度;
  2. 如果以“01”開頭,那么接下來的14個bit表示長度;
  3. 如果以"10"開頭,該byte的剩余6bit廢棄,接著讀入4個bytes表示長度(BigEndian);
  4. 如果以"11"開頭,那么接下來的6個bit表示特殊的編碼格式,一般用來存儲數字:
  • 0表示用接下來的1byte表示長度
  • 1表示用接下來的2bytes表示長度;
  • 2表示用接下來的4bytes表示長度;

String編碼

該編碼方式首先采用Length編碼 進行解析:

  1. 從上面的Length編碼知道,如果以"00","01","10"開頭,首先讀取長度;然后從接下來的內容中讀取指定長度的字符;
  2. 如果以"11"開頭,而且接下來的6個字節為“0”、“1”和“2”,那么直接讀取接下來的1,2,4bytes做為字符串的內容(實際上存儲的是數字,只不過按照字符串的格式存儲);
  3. 如果以“11”開頭,而且接下來的6個字節為"3",表明采用LZF壓縮字符串格式:

LZF編碼的解析步驟為:

  1. 首先采用Length編碼讀取壓縮后字符串的長度clen;
  2. 接著采用Length編碼讀取壓縮前的字符串長度;
  3. 讀取clen長度的字節,并采用lzf算法解壓得到原始的字符串

Score編碼

  1. 讀取1個字節,如果為255,則返回負無窮;
  2. 如果為254,返回正無窮;
  3. 如果為253,返回非數字;
  4. 否則,將該字節的值做為長度,讀取該長度的字節,將結果做為分值;

Value編碼

Redis中的value編碼包括如下類型:

類型名稱 類型代碼
String Encoding 0
List Encoding 1
Set Encoding 2
Sorted Set Encoding 3
Hash Encoding 4
Zipmap Encoding 9
Ziplist Encoding 10
Intset Encoding 11
Sorted Set in Ziplist Encoding 12
Hashmap in Ziplist Encoding 13

其中String編碼在前面已經介紹過,接下來逐一介紹其他的9種編碼方式;

List

  1. 首先用Length編碼讀取List的長度lsize
  2. 采用String編碼讀取lsize個字符串

Set

同List

Sorted Set

  1. 首先用Length編碼讀取Sorted Set的長度zsize
  2. 采用String編碼讀取字符串,采用Score編碼讀取分值;
  3. 循環讀取zsize次;

Hash

  1. 采用Length編碼讀取Hash的大小hsize
  2. 采用String編碼讀取2*hsize的字符串,按照key,value的方式組裝成Map

Zipmap

用于存儲hashmap,Redis2.6之后,該編碼被廢棄,轉而采用Ziplist編碼;

采用String編碼讀取整個zipmap字符串,hashmap字符串的格式為:

<zmlen><len>"foo"<len><free>"bar"<len>"hello"<len><free>"world"<zmend>
  1. zmlen:一個字節,Zipmap的大小;如果>=254,意味著zipmap的大小無法直接獲取到,必須要遍歷整個zipmap才能得到大小;
  2. len:字符串長度,1或5個字節長度;如果第一個字節在0~252之間,那么長度為第一個字節;如果為253,那么接下來的4個字節表示長度;254和255是無效值;
  3. free:1字節,表明value空閑的字節數;
  4. zmend:0xff,表示Zipmap的結尾;

Ziplist

采用String編碼讀取整個ziplist字符串,字符串的格式為:

<zlbytes><zltail><zllen><entry><entry><zlend>
  1. zlbytes:4字節無符號整數,表示ziplist占用的總字節數;
  2. zltail:4字節無符號整數(little endian),表示尾元素的偏移量;
  3. zllen:2字節無符號整數(little endian),表示ziplist中的元素個數, 當元素個數大于65535時,無法用2字節表示,需要遍歷列表獲取元素個數;
  4. entry:ziplist中的元素;
  5. zlend:常量(0xff),表示ziplist的結尾;

entry的格式:

<length-prev-entry><encoding><content>
  1. lenth-prev-entry:如果第一個字節<254,則用1bytes表示長度;否則則用接下來的4bytes(無符號整數)表示長度;
  2. encoding
  • "00"開頭:字符串,用接下來的6bit表示長度;
  • "01"開頭:字符串,用接下來的14bit表示長度;
  • "10"開頭:字符串,忽略本字節的6bit,用接下來的32bit表示長度;
  • "11000000"開頭:整數,內容為接下來的16bit;
  • "11010000"開頭:整數,內容為接下來的32bit;
  • "11100000"開頭:整數,內容為接下來的64bit;
  • "11110000"開頭:整數,內容為接下來的24bit;
  • "11111110"開頭:整數,內容為接下來的8bit;
  • "1111"開頭 :整數,內容為接下來的4bit的值減去1;
  1. content
    entry內容,它的長度通過前面的encoding確定;

注意:元素長度、內容長度等都是采用Little Endian編碼;

Intset

Intset是一個整數組成的二叉樹;當set的所有元素都是整形的時候,Redis會采用該編碼進行存儲;Inset最大可以支持64bit的整數,做為優化,如果整數可以用更少的字節數表示,Redis可能會用16~32bit來表示;注意的是當插入一個長度不一樣的整數時,有可能會引起整個存儲結構的變化

由于Intset是一個二叉樹,因此它的元素都是排序過的;
采用String編碼讀取整個intset字符串,字符串的格式為:

<encoding><length-of-contents><contents>
  1. encoding:32bit的無符號整數;可選值包括2、4和8;表示inset中的每個整數占用的字節數;
  2. length-of-contents:32bit無符號整數,表示Intset中包含的整數個數;
  3. contents:整數數組,長度由length-of-contents決定;

Sorted Set in Ziplist Encoding

采用Ziplist編碼,區別在于用兩個entry分別表示元素和分值;

Hashmap in Ziplist Encoding

采用Ziplist編碼,區別在于用兩個entry分別表示key和value;

代碼樣例

代碼樣例請參考github上的例子redis-sync

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Redis的內存優化 聲明:本文內容來自《Redis開發與運維》一書第八章,如轉載請聲明。 Redis所有的數據都...
    meng_philip123閱讀 18,934評論 2 29
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • 雖然已經十一點了,但是還是按耐不住激動的心情,從下午四點半到剛剛,除了吃飯時間,我花了整整六個小時來完成這幅作品。...
    婭妮妮閱讀 464評論 4 6
  • 星期六 晴 每日一我 周六了,放松睡覺天, 起得晚,然后睡了整個下午。 每日一善 做完了火辣健身的維密女神核心訓練...
    sophietyl閱讀 207評論 0 0
  • 今天,高興。夏雨后的天驚人的清爽,你連拍幾張,叫我連連興奮。連拍的照片相似度強,連拍就連拍吧,只要咱都高興,又遇上...
    婁婁姐閱讀 428評論 0 1