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表明數(shù)據(jù)庫的哪個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個字節(jié)
    $value-type         #1個字節(jié)揖铜,表明數(shù)據(jù)類型:set,map等
    $string-encoded-key #key值茴丰,字符串類型
    $encoded-value      #value,編碼方式和類型有關
    
  2. expire為millisecond

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

    $value-type         #數(shù)據(jù)類型,1個字節(jié)
    $string-encoded-key #key贿肩,字符串類型
    $encoded-value      #value,編碼方式和類型有關
    

Footer

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

編碼算法說明

Length編碼

長度采用BigEndian格式存儲汰规,為無符號整數(shù)

  1. 如果以"00"開頭,那么接下來的6個bit表示長度物邑;
  2. 如果以“01”開頭溜哮,那么接下來的14個bit表示長度滔金;
  3. 如果以"10"開頭,該byte的剩余6bit廢棄茬射,接著讀入4個bytes表示長度(BigEndian)鹦蠕;
  4. 如果以"11"開頭,那么接下來的6個bit表示特殊的編碼格式在抛,一般用來存儲數(shù)字:
  • 0表示用接下來的1byte表示長度
  • 1表示用接下來的2bytes表示長度钟病;
  • 2表示用接下來的4bytes表示長度;

String編碼

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

  1. 從上面的Length編碼知道刚梭,如果以"00","01","10"開頭肠阱,首先讀取長度;然后從接下來的內(nèi)容中讀取指定長度的字符朴读;
  2. 如果以"11"開頭屹徘,而且接下來的6個字節(jié)為“0”、“1”和“2”,那么直接讀取接下來的1衅金,2噪伊,4bytes做為字符串的內(nèi)容(實際上存儲的是數(shù)字,只不過按照字符串的格式存儲)氮唯;
  3. 如果以“11”開頭鉴吹,而且接下來的6個字節(jié)為"3",表明采用LZF壓縮字符串格式:

LZF編碼的解析步驟為:

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

Score編碼

  1. 讀取1個字節(jié)惩琉,如果為255豆励,則返回負無窮;
  2. 如果為254瞒渠,返回正無窮良蒸;
  3. 如果為253,返回非數(shù)字伍玖;
  4. 否則嫩痰,將該字節(jié)的值做為長度,讀取該長度的字節(jié)窍箍,將結果做為分值串纺;

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編碼在前面已經(jīng)介紹過,接下來逐一介紹其他的9種編碼方式仔燕;

List

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

Set

同List

Sorted Set

  1. 首先用Length編碼讀取Sorted Set的長度zsize
  2. 采用String編碼讀取字符串,采用Score編碼讀取分值晰搀;
  3. 循環(huán)讀取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:一個字節(jié)蠕蚜,Zipmap的大小悔橄;如果>=254,意味著zipmap的大小無法直接獲取到靶累,必須要遍歷整個zipmap才能得到大小癣疟;
  2. len:字符串長度挣柬,1或5個字節(jié)長度;如果第一個字節(jié)在0~252之間睛挚,那么長度為第一個字節(jié)邪蛔;如果為253,那么接下來的4個字節(jié)表示長度;254和255是無效值扎狱;
  3. free:1字節(jié),表明value空閑的字節(jié)數(shù)侧到;
  4. zmend:0xff,表示Zipmap的結尾;

Ziplist

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

<zlbytes><zltail><zllen><entry><entry><zlend>
  1. zlbytes:4字節(jié)無符號整數(shù)匠抗,表示ziplist占用的總字節(jié)數(shù);
  2. zltail:4字節(jié)無符號整數(shù)(little endian),表示尾元素的偏移量遭贸;
  3. zllen:2字節(jié)無符號整數(shù)(little endian),表示ziplist中的元素個數(shù), 當元素個數(shù)大于65535時戈咳,無法用2字節(jié)表示心软,需要遍歷列表獲取元素個數(shù)壕吹;
  4. entry:ziplist中的元素;
  5. zlend:常量(0xff),表示ziplist的結尾删铃;

entry的格式:

<length-prev-entry><encoding><content>
  1. lenth-prev-entry:如果第一個字節(jié)<254,則用1bytes表示長度耳贬;否則則用接下來的4bytes(無符號整數(shù))表示長度;
  2. encoding
  • "00"開頭:字符串,用接下來的6bit表示長度猎唁;
  • "01"開頭:字符串咒劲,用接下來的14bit表示長度;
  • "10"開頭:字符串,忽略本字節(jié)的6bit,用接下來的32bit表示長度诫隅;
  • "11000000"開頭:整數(shù)腐魂,內(nèi)容為接下來的16bit;
  • "11010000"開頭:整數(shù)逐纬,內(nèi)容為接下來的32bit蛔屹;
  • "11100000"開頭:整數(shù),內(nèi)容為接下來的64bit豁生;
  • "11110000"開頭:整數(shù)兔毒,內(nèi)容為接下來的24bit漫贞;
  • "11111110"開頭:整數(shù),內(nèi)容為接下來的8bit育叁;
  • "1111"開頭 :整數(shù)迅脐,內(nèi)容為接下來的4bit的值減去1;
  1. content
    entry內(nèi)容豪嗽,它的長度通過前面的encoding確定谴蔑;

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

Intset

Intset是一個整數(shù)組成的二叉樹龟梦;當set的所有元素都是整形的時候树碱,Redis會采用該編碼進行存儲;Inset最大可以支持64bit的整數(shù)变秦,做為優(yōu)化成榜,如果整數(shù)可以用更少的字節(jié)數(shù)表示,Redis可能會用16~32bit來表示蹦玫;注意的是當插入一個長度不一樣的整數(shù)時赎婚,有可能會引起整個存儲結構的變化

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

<encoding><length-of-contents><contents>
  1. encoding:32bit的無符號整數(shù)福贞;可選值包括2撩嚼、4和8;表示inset中的每個整數(shù)占用的字節(jié)數(shù)挖帘;
  2. length-of-contents:32bit無符號整數(shù)完丽,表示Intset中包含的整數(shù)個數(shù);
  3. contents:整數(shù)數(shù)組拇舀,長度由length-of-contents決定逻族;

Sorted Set in Ziplist Encoding

采用Ziplist編碼,區(qū)別在于用兩個entry分別表示元素和分值骄崩;

Hashmap in Ziplist Encoding

采用Ziplist編碼聘鳞,區(qū)別在于用兩個entry分別表示key和value;

代碼樣例

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

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市要拂,隨后出現(xiàn)的幾起案子抠璃,更是在濱河造成了極大的恐慌,老刑警劉巖脱惰,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搏嗡,死亡現(xiàn)場離奇詭異,居然都是意外死亡枪芒,警方通過查閱死者的電腦和手機彻况,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門谁尸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人纽甘,你說我怎么就攤上這事良蛮。” “怎么了悍赢?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵决瞳,是天一觀的道長。 經(jīng)常有香客問我左权,道長皮胡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任赏迟,我火速辦了婚禮屡贺,結果婚禮上,老公的妹妹穿的比我還像新娘锌杀。我一直安慰自己甩栈,他們只是感情好,可當我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布糕再。 她就那樣靜靜地躺著量没,像睡著了一般。 火紅的嫁衣襯著肌膚如雪突想。 梳的紋絲不亂的頭發(fā)上殴蹄,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天,我揣著相機與錄音猾担,去河邊找鬼袭灯。 笑死,一個胖子當著我的面吹牛垒探,可吹牛的內(nèi)容都是我干的妓蛮。 我是一名探鬼主播怠李,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼圾叼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了捺癞?” 一聲冷哼從身側響起夷蚊,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎髓介,沒想到半個月后惕鼓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡唐础,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年箱歧,在試婚紗的時候發(fā)現(xiàn)自己被綠了矾飞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡呀邢,死狀恐怖洒沦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情价淌,我是刑警寧澤申眼,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站蝉衣,受9級特大地震影響括尸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜病毡,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一濒翻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧啦膜,春花似錦肴焊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至啸臀,卻和暖如春届宠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乘粒。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工豌注, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灯萍。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓轧铁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親旦棉。 傳聞我的和親對象是個殘疾皇子齿风,可洞房花燭夜當晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Redis的內(nèi)存優(yōu)化 聲明:本文內(nèi)容來自《Redis開發(fā)與運維》一書第八章,如轉載請聲明绑洛。 Redis所有的數(shù)據(jù)都...
    meng_philip123閱讀 18,901評論 2 29
  • 1. Java基礎部分 基礎部分的順序:基本語法救斑,類相關的語法,內(nèi)部類的語法真屯,繼承相關的語法脸候,異常的語法,線程的語...
    子非魚_t_閱讀 31,665評論 18 399
  • 雖然已經(jīng)十一點了泵额,但是還是按耐不住激動的心情,從下午四點半到剛剛携添,除了吃飯時間梯刚,我花了整整六個小時來完成這幅作品。...
    婭妮妮閱讀 455評論 4 6
  • 星期六 晴 每日一我 周六了薪寓,放松睡覺天亡资, 起得晚,然后睡了整個下午向叉。 每日一善 做完了火辣健身的維密女神核心訓練...
    sophietyl閱讀 196評論 0 0
  • 今天锥腻,高興。夏雨后的天驚人的清爽母谎,你連拍幾張瘦黑,叫我連連興奮。連拍的照片相似度強奇唤,連拍就連拍吧幸斥,只要咱都高興,又遇上...
    婁婁姐閱讀 409評論 0 1