Redis5.0 RDB文件超详细解析
Redis RDB介绍
RDB
是 Redis 将 server 端的内存中的 k/v 对以二进制的方式,持久化存储的一种文件形式。
文件中,一般会以 对象的长度+对象 的格式来存储,只要根据这个格式,就能渐进的遍历整个文件。Redis
还支持开启 LZF
的压缩算法,可以牺牲CPU时间,来减少 RDB
文件的大小;如果开启LZF
并且超过20
个bytes时,
会将压缩后的字符写入文件。
RDB文件格式
➜ go-redis-parser od -A x -t x1c -v ./teststub/dumpV9.rdb 000000 52 45 44 49 53 30 30 30 39 fa 09 72 65 64 69 73 R E D I S 0 0 0 9 372 \t r e d i s 000010 2d 76 65 72 05 35 2e 30 2e 35 fa 0a 72 65 64 69 - v e r 005 5 . 0 . 5 372 \n r e d i 000020 73 2d 62 69 74 73 c0 40 fa 05 63 74 69 6d 65 c2 s - b i t s 300 @ 372 005 c t i m e 302 000030 71 8a 8d 5d fa 08 75 73 65 64 2d 6d 65 6d c2 30 q 212 215 ] 372 \b u s e d - m e m 302 0 000040 e0 0f 00 fa 0c 61 6f 66 2d 70 72 65 61 6d 62 6c 340 017 \0 372 \f a o f - p r e a m b l 000050 65 c0 00 fe 00 fb 06 00 f9 00 00 01 73 01 61 f9 e 300 \0 376 \0 373 006 \0 371 \0 \0 001 s 001 a 371 000060 03 0e 02 6c 69 01 11 11 00 00 00 0d 00 00 00 02 003 016 002 l i 001 021 021 \0 \0 \0 \r \0 \0 \0 002 000070 00 00 01 61 03 01 62 ff f9 00 02 03 73 65 74 02 \0 \0 001 a 003 001 b 377 371 \0 002 003 s e t 002 000080 01 62 01 61 f9 00 0f 06 73 74 72 65 61 6d 01 10 001 b 001 a 371 \0 017 006 s t r e a m 001 020 000090 00 00 01 6d 70 b5 4a 7e 00 00 00 00 00 00 00 00 \0 \0 001 m p 265 J ~ \0 \0 \0 \0 \0 \0 \0 \0 0000a0 40 52 52 00 00 00 18 00 03 01 00 01 02 01 84 6e @ R R \0 \0 \0 030 \0 003 001 \0 001 002 001 204 n 0000b0 61 6d 65 05 83 61 67 65 04 00 01 02 01 00 01 00 a m e 005 203 a g e 004 \0 001 002 001 \0 001 \0 0000c0 01 87 4c 61 6d 62 65 72 74 08 1d 01 05 01 02 01 001 207 L a m b e r t \b 035 001 005 001 002 001 0000d0 f2 33 8c 00 04 00 01 84 4a 61 63 6b 05 1a 01 05 362 3 214 \0 004 \0 001 204 J a c k 005 032 001 005 0000e0 01 02 01 f2 9c ad 00 04 00 01 83 54 6f 6d 04 1e 001 002 001 362 234 255 \0 004 \0 001 203 T o m 004 036 0000f0 01 05 01 ff 03 81 00 00 01 6d 70 b5 f8 1a 00 01 001 005 001 377 003 201 \0 \0 001 m p 265 370 032 \0 001 000100 05 67 72 6f 75 70 00 00 00 00 f9 00 0c 04 7a 73 005 g r o u p \0 \0 \0 \0 371 \0 \f 004 z s 000110 65 74 15 15 00 00 00 12 00 00 00 04 00 00 01 61 e t 025 025 \0 \0 \0 022 \0 \0 \0 004 \0 \0 001 a 000120 03 f2 02 01 62 03 f3 ff f9 03 0d 01 68 11 11 00 003 362 002 001 b 003 363 377 371 003 \r 001 h 021 021 \0 000130 00 00 0d 00 00 00 02 00 00 01 61 03 01 61 ff ff \0 \0 \r \0 \0 \0 002 \0 \0 001 a 003 001 a 377 377 000140 0e e0 f7 31 2f 37 16 df 016 340 367 1 / 7 026 337 000148
这是一个 version 9
的 RDB 文件
魔数 Magic Number
文件前 9 个字节是一个 魔数
,5 个字节Redis
和 4 个字节的版本号 009
。
辅助字段 Aux Fields
通用字符串字段,用于向RDB添加状态,Version 7
加入的,向后兼容。AUX字段由两个字符串组成:键和值
。
整理了下,除了 lua
,有这些字段:
- redis-ver:版本号
- redis-bits:OS Arch
- ctime:RDB文件创建时间
- used-mem:使用内存大小
- repl-stream-db:在server.master客户端中选择的数据库
- repl-id:当前实例 replication ID
- repl-offset:当前实例复制的偏移量
数据库索引
fe(0xfe),fb(0xfb)是 10 进制的 254 和 251,在 RDB 分别对应着,SELECT_DB
和RESIZE_DB
。 每一个SELECTDB
后都会紧跟着RESIZEDB
,后者表示的是当前数据库hashtable
键大小的提示,每次切换数据库时提前读到,避免不必要的rehash
。
数据库键值对
接下来,读到的就是Redis
中所有存储着的K/V
对:
LFU/LRU Idle
后面f9(0xf9)是 10 进制的 249,是表示 key 对象的lfu_idle
,这个字段是只有开启maxmemory-policy
并且设置为volatile-lfu
或allkeys-lfu
才会写入文件。LRU
的同理,不过前缀是 f8(0xf8),maxmemory-policy
要设置为:allkeys-lru
和volatile-lru
。
String结构
00(0x00)是 10 进制的 0,表示string
类型的对象,01 指key
是一个字节长度:“s”, value
也是一个字节长度:“a”,
List结构
0e(0x0e)是 10 进制的 14,表示list
类型的对象(在3.2版本之前,是由ziplist
和linkedlist
结构保存,之后存储是quicklist
);2个字节长度的key
:"li",
下来分别是一个长度的items
:"a" 和 "b"
Set结构
2,表示Set
类型对象,3个长度 "set",两个members
:"a" 和 "b"
Stream结构
继 module
之后,redis 在 5.0 增加了新的数据类型 Stream
,不了解的同学可以Google下,很多介绍的文章。根据作者自己说,它也是充分借鉴了 kafka
的设计思想,在已有 list
的基础上增加了另一种流式类型。
基本。
0f(0x0f)是 10 进制的 15,是Stream
类型的对象,5个长度的key
:"stream"。然后是 StreamId
结构体,6d 70 b5 4a 7e
分别是 10 进制的(109 112 181 74 126),二进制 01101101 01110000 10110101 01001010 01111110
,因为毫秒是uint
,加上符号位即:1 01101101 01110000 10110101 01001010 01111110
对应如图所示:first-entry
恰好是创建Stream
的毫秒数,后面跟着8位的随机数0
;然后是entry
结构,每个entry
结构前面,也会有和StreamId
相同的messageId
,这里就不具体逐位分析了。长度是 3,第一个字段:"name";
第二个字段:"age",3个entry
分别是name:Lambert,age:29
、name:Jack,age:26
、name:Tom,age:30
;下来是消费组Group
,名为:Group
的消费组,因为没有任何消费,所以偏移量pending entry list
都是0
。
ZSet结构
0c 是 10 进制的 12,以ziplist
结构存储的Sortedset
类型,4个长度的key
:"zset",接下来的 4 表示:4个元素,zset
会将member
和score
一起保存,所以,就是2组members
;分别是:{memeber:"a",score:1}
、{member:"b",score:2}
。
Hash结构
0d(13) 是RDB_TYPE_HASH_ZIPLIST
,表示是ziplist
存储的hash
类型数据,1 个长度的key:”h”。key
后面的2,存着hash
结构的field
和value
;在 field 和 value 前面的 1,分别是指各自的长度,都是 “a”
文件EOF
ff(255) EOF,在所有数据写完结束后,会以一个EOF结尾
CheckSum
从Version 5
开始,如果在配置文件中开启rdbchecksum yes
,会在RDB
文件的结尾处,用 8 个字节,CRC64
计算整个文件内容的检验和。