redis持久化原理(一)RDB对象保存结构

一.RDB文件特点

  • RDB 文件是一个紧凑的二进制文件
    • rdb文件所有内容都有二进制数据构成,不存在空格等其它字符。也就是说,所有的数据结构、特殊标识等都经过了指定大小或结构的设计。按照严格的步骤“组装”形成rdb文件
  • RDB 文件记录的是 Redis 在某一时刻的完整数据快照,而不是实时更新的数据。
  • RDB 文件使用了内部优化和压缩算法
    • 在redis3.0版本中使用LZF压缩算法对过长的字符串进行压缩,需要知道rdb文件实际上不追求极致的空间压缩,因为过多的压缩会降低保存和载入效率,所以为了提升效率,除了长字符串以外的数据不会被压缩而直接转换成二进制进行存储。
  • 适合大规模备份
    • 在复制,集群模式中,从节点需要使用SYNC同步主服务器上的数据,这时rdb文件就是复制的依据。

二.RDB整体文件结构

RDB整体文件结构
RDB整体文件结构

注:全大写字母为常量,小写字母为数据或是变量

由上图可知,RDB文件整体包含五大部分:

  1. REDIS标识(5字节, 不是C字符串所以不带‘\0’结尾)
  2. RDB版本号 (4字节)
  3. 数据部分(不定)
  4. 文件结束标识EOF(end of file 1字节 255)
  5. 校验和 (uint_64,8字节)

三.长度编码 

        长度编码是rdb文件能够载入的基石,无论是对象所包含的数据的个数,还是数据所占用的字节的长度都依靠长度编码完成。例如当前有一个字符对象“nihao”,每个字符占1字节,进行长度编码时就会标注要载入该对象时所需要读取的字节长度为5,确保读取的正确性。

      长度编码时,头两位用来指示长度范围或特殊编码,具体标识如下表

长度编码规则
00 | xxxxxx00开头,长度编码在这一字节的其余 6 位中,占1字节
01 | xxxxxx xxxxxxxx01开头,长度编码位6+8bits,占2字节
10 | xxxxxx [32bits]10开头,长度编码为6+32bits,占5字节
11 | [6bits特殊编码]

11开头,使用6bits标识特殊编码(宏定义)

  1. REDIS_RDB_ENC_INT8 0, 8位整数,占1字节

  2. REDIS_RDB_ENC_INT16 1,16位整数,占2字节

  3. REDIS_RDB_ENC_INT32 2, 32位整数,占4字节

  4. REDIS_RDB_ENC_LZF 3, 压缩字符串

        

四.databases结构

        databases上面介绍的rdb文件整体结构中最为重要也是实际保存数据的地方

databases结构

实际存储中,每一个数据库前都包含SELECTDB常量(同EOF类似, 1字节, 254)

// 以 MS 计算的过期时间
#define REDIS_RDB_OPCODE_EXPIRETIME_MS 252
// 以秒计算的过期时间
#define REDIS_RDB_OPCODE_EXPIRETIME 253
// 选择数据库
#define REDIS_RDB_OPCODE_SELECTDB   254
// 数据库的结尾(但不是 RDB 文件的结尾)
#define REDIS_RDB_OPCODE_EOF        255

 然后是db_number使用上面所讲的长度编码进行操作。

4.1Key_Value_pairs

         key_value_pairs是数据库中的键值对,需要知道,数据库中的键值对有有无过期时间的区别,无过期时间的键值对以【type】【key】【value】格式存储在rdb文件中,而有过期时间的键值对以【EXPIRETIME】【time】【type】【key】【value】。如下图:

无过期时间键值对
有过期时间键值对

 key

        我们知道,redis中的key都是string对象,所以无需对key进行类型标注,上面结构中的type是对value的标注。所以key的结构同value中string的结构相同。接下来我们着重介绍一下value中不同类型的rdb保存结构和操作。

value

        对象类型类型

        基础类型包含STRING/LIST/SET/ZSET/HASH,所以0-4默认编码(注释是默认底层实现),9-13是数据量较小或是特殊情况下(如set只包含整数时)的底层实现。下面的宏定义对应了上述结构中的TYPE数据。

/*
 * 对象类型在 RDB 文件中的类型
 */
#define REDIS_RDB_TYPE_STRING 0 
#define REDIS_RDB_TYPE_LIST   1 //双链表
#define REDIS_RDB_TYPE_SET    2 //哈希表
#define REDIS_RDB_TYPE_ZSET   3 //跳表
#define REDIS_RDB_TYPE_HASH   4 //哈希表

/*
 * 对象的编码方式
 */
#define REDIS_RDB_TYPE_HASH_ZIPMAP    9
#define REDIS_RDB_TYPE_LIST_ZIPLIST  10
#define REDIS_RDB_TYPE_SET_INTSET    11
#define REDIS_RDB_TYPE_ZSET_ZIPLIST  12
#define REDIS_RDB_TYPE_HASH_ZIPLIST  13
1.string对象

        字符串string对象在保存时和长度编码中的特殊编码紧密相关,因为在redis中字符串对象包含了三种编码形式

  • int
  • embstr
  • raw

        当string是int编码或字符串过长时长度编码可能会采用“11 | [6bits特殊编码]”形式,而其它情况下一般以保存,例如:

        但是当因为字符串过长而需要采用LZF压缩时,存储结构将会改变成下图形式

LZF压缩后保存
2.list对象

        当list对象的编码为linklist时,存储结构如下:

 因为在redis中list、set和zset中存储的数据类型只能是string类型(包含int,embstr,raw三种编码),所以其中item是结构,例如:

3.set对象

        当set对象的编码是HashTable时,直接将哈希表中的键作为值,存储结构如下:

其中element结构于list类似,不再赘述。 

4.hash对象

        当hash对象的编码是HashTable时,存储结构如下:

其中的key_value_pair于数据库中哈希表的key_value_pairs的保存不相同,这里的value不指明type,因为只能够是string对象类型,因此上面图的结构可以看成:

 例如:

5.zset对象
         当zset对象的编码是zskiplist时,存储结构如图:

例如:

 6.特殊编码intset和ziplist

        当需要持久化的对象类型编码为intset或是ziplist时,会将其转换成字符串对象,然后进行整体储存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值