网站首页 > 技术文章 正文
RDB文件解析
Redis的RDB文件是一个二进制文件,用于持久化内存数据,是内存数据某一时刻的快照文件,Redis启动时候通过读取该文件将键值对加载到内存中还原Redis最新的状态.
目前该RDB文件最新版本为version 9,
以下为RDB文件版本变更历史
- Version 9 – redis 5.0
- Version 8 – redis 4.0
- Version 7 – redis 3.2
- Version 6 – redis 2.8
- Version 5 – redis 2.4
这里需要注意的是,我们可以将低版本的Redis持久化RDB文件导入到高版本的RDB文件中,即高版本兼容低版本,也可以同版本互相导入,但是不能从高版本导入到低版本的RDB文件.
例如,Redis3.2的RDB文件版本为version7,该RDB文件可以在Redis>=3.2的版本中正常加载,但是无法加载到Redis<3.2的版本中.
RDB版本号在RDB二进制文件的头部数据中, 在linux中可以通过od,xxd等命令将二进制文件以十六进制数据格式查看.
为了便于快速高效的对RDB文件进行读写,Redis采用LZF压缩算法来减少文件的大小,在Redis底层数据结构中,每个对象都会有一个相应大小的前缀用来描述该对象占用的字节数长度等,因此Redis在加载该RDB文件时,读取的每个对象Redis都会知道应该为它分配多大的内存空间.
一个Redis RDB文件典型的格式如下(以 RDB version 9为例)
----------------------------# RDB文件是二进制的,所以并不存在回车换行来分隔一行一行
52 45 44 49 53 #这里的数字两个为一字节,代表的是一个字符对应的ascii码, 这里是5个字节的字符串常量"REDIS",Redis读取该文件可以判断是否为RDB文件
30 30 30 39 #同上,4个字节的RDB版本号, 版本 = "0007" = 7
----------------------------
FA #FA表示辅助字段
$string-encoded-key # 可能包含任意元数据信息
$string-encoded-value # 例如Redis的版本、创建时间、已使用的内存等等...
----------------------------
FE 00 # FE指明接下来的键值对数据所属数据库编号. 00代表数据库编号为0
----------------------------
FB # 指明resizedb属性(针对hash表)
$length-encoded-int # 相应Hash表的大小,1字节
$length-encoded-int # 相应带失效时间的Hash表大小,1字节
----------------------------# Key-Value 对存储开始
FD $unsigned int # FD表示秒级别的过期,时间,接下来用4字节的无符号整数表示,过期时间是用 length encoding 编码存储.
$value-type # 用1字节表示键的类型
$string-encoded-key # 使用Redis字符串编码方式的键
$encoded-value # 使用$value-type指明的编码方式的值
----------------------------
FC $unsigned long # FCF表示毫秒级别的超时时间,紧接着是8字节的无符号整数,过期时间是用 length encoding 编码存储.
$value-type # 用1字节表示键的类型,如set,hash,list,zset等
$string-encoded-key # 键,通过string encoding 编码
$encoded-value # 值,根据不同的value type采用不同的编码方式
----------------------------
$value-type # 没有失效时间的键的类型
$string-encoded-key # 使用Redis字符串编码方式的键
$encoded-value # 使用$value-type指明的编码方式的值
----------------------------
FE $length-encoding # 下一个库开始,库的编号用 length encoding 编码.
----------------------------
... # 附加的关于该数据库的其他信息
FF # RDB文件结束标识
8 byte checksum # 8字节的CRC64表示的文件校验和
首先在redis的10和11数据库写入如下测试数据.
$ redis-cli -n 10
127.0.0.1:6379[10]> hset userid0001 username zhang,quan
127.0.0.1:6379[10]> hset userid0001 gender male
127.0.0.1:6379[10]> hset userid0001 address Oregon
127.0.0.1:6379[10]> select 11
127.0.0.1:6379[11]> set userid0001 21 ex 18000
127.0.0.1:6379[11]> save
通过od命令将二进制文件的RDB文件以十六进制的格式展示(od -A x -t x1c -v dump.rdb)
[redis@ec2-redis-01 data]$ od -A x -t x1c -v dump.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 39 fa 0a 72 65 64 69
- v e r 005 5 . 0 . 9 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 72 d2 3f 5f fa 08 75 73 65 64 2d 6d 65 6d c2 60
r 322 ? _ 372 \b u s e d - m e m 302 `
000040 6b 39 00 fa 0c 61 6f 66 2d 70 72 65 61 6d 62 6c
k 9 \0 372 \f a o f - p r e a m b l
000050 65 c0 00 fe 0a fb 01 00 f8 4e 57 0d 0a 75 73 65
e 300 \0 376 \n 373 001 \0 370 N W \r \n u s e
000060 72 69 64 30 30 30 31 40 40 40 00 00 00 37 00 00
r i d 0 0 0 1 @ @ @ \0 \0 \0 7 \0 \0
000070 00 06 00 00 08 75 73 65 72 6e 61 6d 65 0a 0a 7a
\0 006 \0 \0 \b u s e r n a m e \n \n z
000080 68 61 6e 67 2c 71 75 61 6e 0c 06 67 65 6e 64 65
h a n g , q u a n \f 006 g e n d e
000090 72 08 04 6d 61 6c 65 06 07 61 64 64 72 65 73 73
r \b 004 m a l e 006 \a a d d r e s s
0000a0 09 06 4f 72 65 67 6f 6e ff fe 0b fb 01 01 fc bd
\t 006 O r e g o n 377 376 \v 373 001 001 374 275
0000b0 af 60 12 74 01 00 00 f8 02 00 0a 75 73 65 72 69
257 ` 022 t 001 \0 \0 370 002 \0 \n u s e r i
0000c0 64 30 30 30 31 c0 15 ff 29 d9 2c 0c 22 9b be 19
d 0 0 0 1 300 025 377 ) 331 , \f " 233 276 031
0000d0
查看ascii码表(linux命令"man ascii"可以看到)
2 3 4 5 6 7 30 40 50 60 70 80 90 100 110 120
------------- ---------------------------------
0: 0 @ P ` p 0: ( 2 < F P Z d n x
1: ! 1 A Q a q 1: ) 3 = G Q [ e o y
2: " 2 B R b r 2: * 4 > H R \ f p z
3: # 3 C S c s 3: ! + 5 ? I S ] g q {
4: $ 4 D T d t 4: " , 6 @ J T ^ h r |
5: % 5 E U e u 5: # - 7 A K U _ i s }
6: & 6 F V f v 6: $ . 8 B L V ` j t ~
7: ′ 7 G W g w 7: % / 9 C M W a k u DEL
8: ( 8 H X h x 8: & 0 : D N X b l v
9: ) 9 I Y i y 9: ′ 1 ; E O Y c m w
A: * : J Z j z
B: + ; K [ k {
C: , < L \ l |
D: - = M ] m }
E: . > N ^ n ~
F: / ? O _ o DEL
魔术字符串REDIS
Redis RDB文件以"REDIS"五个字符开头,占用5个字节,如上述十六进制的"52 45 44 49 53",分别代表" R E D I S"
000000 52 45 44 49 53
R E D I S 0 0 0 9 372 \t r e d i s
RDB版本
接下来的4个字节记录了RDB的版本号
000000 52 45 44 49 53 30 30 30 39
0 0 0 9
操作码
在以上REDIS和RDB版本头部信息加载完成后,后续的每个部分均由一个指定的操作码引入
十六进制 名称 代表含义
0xFA AUX 辅助字段
0xFE SELECTDB 数据库选择器
0xFB RESIZEDB 数据库中哈希表和带有TTL哈希表的数量
0xFD EXPIRETIME 键的失效时间(秒级别)
0xFC EXPIRETIMEMS 键的失效时间(毫秒级别)
0xFF EOF RDB文件的结尾
辅助字段
辅助字段以0xFA开始,用来描述Redis实例的一些信息,每个信息以键值对的形式出现,例如
- redis-ver: redis版本号
- redis-bits: redis架构
- ctime: RDB创建时间
- used-mem: 使用内存
- repl-stream-db: 在server.master客户端中选择的数据库
- repl-id: 当前实例的复制ID
- repl-offset: 当前实例复制的偏移量
- aof-preamble: aof混合持久化
000010 2d 76 65 72 05 35 2e 30 2e 39 fa 0a 72 65 64 69
- v e r 005 5 . 0 . 9 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 27 c4 3f 5f fa 08 75 73 65 64 2d 6d 65 6d c2 80
' 304 ? _ 372 \b u s e d - m e m 302 200
000040 6b 39 00 fa 0c 61 6f 66 2d 70 72 65 61 6d 62 6c
k 9 \0 372 \f a o f - p r e a m b l
000050 65 c0 00 fe 0a fb 01 00 f8 0c 0d 0a 75 73 65 72
e 300 \0 376 \n 373 001 \0 370 \f \r \n u s e r
SELECTDB(数据库选择器)
一个Redis实例可能有多个数据库,RDB文件以一个字节的0xFE标识数据库选择器部分的开始,在该字节后,一个变长的字段表示数据库的索引值。
000050 65 c0 00 fe 0a fb 01 00 f8 0c 0d 0a 75 73 65 72
10
......
0000a0 09 06 4f 72 65 67 6f 6e ff fe 0b fb 01 01 fc bd
11
RESIZEDB(哈希表信息)
RDB在version 7中引入resizedb操作码概念,RDB文件以一字节的0xFB标识RESIZEDB,通过调整哈希表大小的操作码RESIZEDB,redis可以更快的读RDB文件,在RESIZEDB操作码之后的两个值是:
- 数据库的哈希表大小
- 失效哈希表的大小
000050 65 c0 00 fe 0a fb 01 00 f8 4e 57 0d 0a 75 73 65
1 0
......
0000a0 09 06 4f 72 65 67 6f 6e ff fe 0b fb 01 01 fc bd
1 1
key-value键值对
在RESIZEDB之后,包含是数据库选择器一系列的KV键值对序列,每个key-value由四部分组成
- key expiry time: 键失效时间戳,这个字段是可选的.
- value type: 一个字节的标识符,指明Value的类型.
- key值: Key被当作一个Redis字符串进行编码.
- value值: 值的编码方式根据Value Type字段决定.
000050 65 c0 00 fe 0a fb 01 00 f8 45 c9 0d 0a 75 73 65
370 E 311 \r \n u s e
000060 72 69 64 30 30 30 31 40 40 40 00 00 00 37 00 00
r i d 0 0 0 1 @ @ @ \0 \0 \0 7 \0 \0
000070 00 06 00 00 08 75 73 65 72 6e 61 6d 65 0a 0a 7a
\0 006 \0 \0 \b u s e r n a m e \n \n z
000080 68 61 6e 67 2c 71 75 61 6e 0c 06 67 65 6e 64 65
h a n g , q u a n \f 006 g e n d e
000090 72 08 04 6d 61 6c 65 06 07 61 64 64 72 65 73 73
r \b 004 m a l e 006 \a a d d r e s s
0000a0 09 06 4f 72 65 67 6f 6e ff fe 0b fb 02 01 f8 02
\t 006 O r e g o n 377 376 \v 373 002 001 370 002
key expiry time
该部分由一个字节标识开始,该表示可以是以下两种之一:
- 0xFD: 该标识表示,失效时间以秒为单位,接下来的4个字节组成一个无符号的整型,表示Unix时间戳.
- 0xFC: 该标识表示,失效时间以毫秒为单位,接下来的8个字节组成一个无符号的长整型,表示Unix时间戳.
在导入过程中,如果key失效了,会须被忽略掉.
value type
一个字节来表示value使用的编码方式。
- 0 = String编码
- 1 = List编码
- 2 = Set编码
- 3 = SortedSet编码
- 4 = Hash编码
- 9 = ZipMap编码
- 10 = ZipList编码
- 11 = IntSet编码
- 12 = Sorted Set in ZipList编码
- 13 = Hashmap in ZipList编码(RDB版本4引入)
- 14 = List in QuickList编码 (RDB版本7引入)
Key
Key被当作一个Redis字符串进行编码.
value
值的编码方式根据Value Type字段决定.
- 当value type为0,值是一个简单的字符串.
- 当value type为1,2,3或4,值是字符串序列,这一系列的字符串用于构建list,set,hash和zset 结构.
- 当value type为9,10,11或12,值被封装在字符串中,在读取出来后需要进一步解析.
Length Encoding(长度编码)
上面提到FD(秒级别)和FC(毫秒级别)分别占用4字节和8字节的长度来表示键的过期时间,采用Length Encoding编码来存储,这里所说的Length Encoding用来存储数据流中下一个对象的长度,是一种可变字节编码,旨在减少字节开销,将不同大小的数字编码成不同的长度.
那么Length encoding是如何工作的呢?
- 首先在读取长度时,会读取一个字节的数据,其中前两位用来变长编码判断.
- 如果前两位是 0 0,那么下面剩下的 6位就表示具体长度.
- 如果前两位是 0 1,那么会再读取一个字节的数据,加上前面剩下的6位,共14位用于表示具体长度.
- 如果前两位是 1 0,那么剩下的 6位就被废弃了,取而代之的是再读取后面的4 个字节用于表示具体长度.
- 如果前两位是 1 1,那么下面的应该是一个特殊编码,剩下的 6位用于标识特殊编码的种类.特殊编码主要用于将数字存成字符串,或者编码后的字符串,具体见 “String Encoding”.
通过可变长编码带来如下好处.
- 0 – 63的数字只需要一个字节进行存储.
- 而64 – 16383 的数字只需要两个字节进行存储.
- 16383 - 2^32 -1 的数字只需要用5个字节(1个字节的标识加4个字节的值)进行存储.
String Encoding,List Encoding,Set Encoding,Sorted Set Encoding等不同数据库类型的底层编码方案可参考Redis官方网站.
RDB文件分析工具
Rdbtools是一个解析dump.rdb文件,并生成内存报告的分析工具,对我们更好地使用Redis非常有帮助,是一个不可多得的利器,除此之外,该工具还提供额外的功能.
- 生成所有数据库所有类型的键的内存报告.
- 将RDB文件转储为json格式.
- 通过diff工具比较两个rdb文件的差异等.
如何安装Rdbtools
Rdbtools工具使用Python开发,解析RDB文件需要使用以下库文件.
- python-lzf: RDB文件使用lzf压缩算法
- redis-py
通过pip安装
pip install rdbtools python-lzf
安装完成后查看Rdbtools的命令帮助
$ rdb --help
usage: usage: rdb [options] /path/to/dump.rdb
Example : rdb --command json -k "user.*" /var/redis/6379/dump.rdb
positional arguments:
dump_file RDB Dump file to process
optional arguments:
-h, --help show this help message and exit
-c CMD, --command CMD
Command to execute. Valid commands are json, diff,
justkeys, justkeyvals, memory and protocol
-f FILE, --file FILE Output file
-n DBS, --db DBS Database Number. Multiple databases can be provided.
If not specified, all databases will be included.
-k KEYS, --key KEYS Keys to export. This can be a regular expression
-o NOT_KEYS, --not-key NOT_KEYS
Keys Not to export. This can be a regular expression
-t TYPES, --type TYPES
Data types to include. Possible values are string,
hash, set, sortedset, list. Multiple typees can be
provided. If not specified, all data types will be
returned
-b BYTES, --bytes BYTES
Limit memory output to keys greater to or equal to
this value (in bytes)
-l LARGEST, --largest LARGEST
Limit memory output to only the top N keys (by size)
-e {raw,print,utf8,base64}, --escape {raw,print,utf8,base64}
Escape strings to encoding: raw (default), print,
utf8, or base64.
-x, --no-expire With protocol command, remove expiry from all keys
-a N, --amend-expire N
With protocol command, add N seconds to key expiry
time
生成内存报告
$ rdb --command memory dump.rdb -f dump.csv
$ head -n 10 dump.csv
database,type,key,size_in_bytes,encoding,num_elements,len_largest_element,expiry
0,string,ElastiCacheMasterReplicationTimestamp,120,string,24,24,
1,hash,2A9IADAECJ3GV95OF0YJTNHJW,213,ziplist,4,31,
1,hash,3557RNEUH63KXCLL3D8YJOKEH,820,hashtable,6,165,
1,hash,4JYVF4Q8182YAK4K1CAXX0DJH,120,ziplist,1,31,
1,hash,1PZY9WS8GSCXVA7JY8KWC5RRW,120,ziplist,1,31,
1,hash,A3JIPZHUZ8WA1TH6K8JO09FC1,120,ziplist,1,31,
1,hash,180FDGPWBGLG6K8L5T32A14Y8,120,ziplist,1,31,
1,hash,3MCC09SRQSG2SA8I46TOIOD4M,120,ziplist,1,31,
1,hash,3682794E83385JHZJUD5BLQF3,120,ziplist,1,31,
以上各列依次分别代表数据库,键类型,键名,键大小,编码,元素数量,最大元素长度,过期时间.
需要注意的是,键的大小是一个估值,实际占用的内存大小略大于该报告.
将该csv文件导入到关系型数据库中,就可以针对某个特定的数据库或者某个特定类型的键做进一步分析,当然Rdbtools工具也支持针对单个库或者指定类型的键操作.
下面将上述csv文件导入到PostgreSQL数据库.
# create table redis_rdb (
database smallint,
type varchar(12),
key varchar(64),
size_in_bytes integer,
encoding varchar(24),
num_elements smallint,
len_largest_element smallint,
expiry integer
);
postgres=# create index on redis_rdb (key);
postgres=# copy redis_rdb(database, type, key, size_in_bytes, encoding, num_elements, len_largest_element,expiry) from '/usr/local/pgsql/dba/dump.csv' delimiter ',' csv header;
猜你喜欢
- 2024-11-27 「重磅」Xilinx下载文件破解及LUT在线可编程研究
- 2024-11-27 2020年4月Redis面试题和答案整理
- 2024-11-27 自主可控的PLC编程软件:kVPAC/Beremiz操作实践
- 2024-11-27 面试官:说说 Redis 的缓存雪崩、缓存穿透和缓存击穿问题
- 2024-11-27 Redis内存管理:配置与版本事项
- 2024-11-27 Kubernetes全栈架构师(Docker基础)--学习笔记
- 2024-11-27 串口通讯继电器-modbus通信上位机调试软件工具项目开发案例
- 2024-11-27 GCKontrol模型的自动创建
- 2024-11-27 推荐:工业数字化系统开发用到的串口调试小助手
- 2024-11-27 读完这46道Redis面试题之后,你就会觉得自己的Redis白学了
- 11-27echarts图形报表的入门案例
- 11-27Echarts仿电梯运行图
- 11-27微信小程序开发之wepy 引入echarts统计图方法 亲测可用
- 11-27yarn安装echarts教程
- 11-27微信小程序使用 ECharts
- 11-274、echarts 如何画图?(必会)
- 11-27JavaScript 前端数据可视化——ECharts.js
- 11-27vue+echarts使用
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)