数据库状态:将服务器中的非空数据库以及键值对统称为数据库状态

【Redis笔记】RDB持久化_服务器

 

为什么要RDB持久化?

因为redis是内存数据库,将自己的数据库状态储存在内存里面,如果不把内存中的数据库状态保存到磁盘里面,那么一旦服务器退出,服务器中的 数据库状态也会消失不见。

【Redis笔记】RDB持久化_缓存_02

 

RDB文件的创建:

SAVE命令:阻塞Redis服务器进程,直到RDB文件创建完毕为止。

当SAVE命令正在执行时,客户端发送的所有命令都会被拒绝。

BGSAVE命令:派生出一个子进程,然后由子进程负责创建RDB文件,父进程继续处理命令请求。

注意:

(1)BGSAVE命令执行期间,客户端发送的SAVE命令会被服务器拒绝。

原因:为了避免父进程和子进程同时执行两个rdbSave调用,防止产生竞争条件

(2)BGREWRITEAOF和BGSAVE不能同时执行。

原因:两个子进程都同时执行大量的磁盘写入操作,考虑到性能。

RDB文件的载入:

【Redis笔记】RDB持久化_服务器_03

 

Redis服务器在启动时自动载入RDB文件,所以Redis并没有专门载入RDB文件的命令,只要Redis服务器在启动时检测到RDB文件的存在,就会自动载入RDB文件。

注意:

(1)如果服务器开启了AOF持久功能,那么服务器会优先使用AOF来还原数据库状态。

(2)服务器在载入RDB文件期间,会一直处于阻塞状态,直到载入工作完成为止。

BGSAVE的自动间隔性保存:

Redis运行用户通过设置服务器配置的save选项,让服务器每隔一段时间自动执行一次BGSAVE命令。

用户可以通过save选项设置多个保存条件,但只要其中任意一个条件被满足,服务器就会执行BGSAVE命令。

原理:

1、save选项保存在redisServer的saveparams数组中

【Redis笔记】RDB持久化_redis_04

 

【Redis笔记】RDB持久化_服务器_05

【Redis笔记】RDB持久化_数据库_06

 

 

 

【Redis笔记】RDB持久化_数据库_07

 

2

(1)服务器状态维护一个dirty计数器,记录距离上一次成功执行SAVE命令或者BGSAVE命令之后,服务器对数据库状态(服务器中的所有数据库)进行修改的次数(包括写入,删除,更新等操作)

(2)服务器状态维护一个lastsave属性,记录服务器上一次成功执行SAVE命令或者BGSAVE命令的时间

【Redis笔记】RDB持久化_服务器_08

 

3、定时检查保存条件是否满足:

Redis服务器周期性操作函数serverCron默认每隔100毫秒就会执行一次,该函数用于对正在运行的服务器进行维护,它的其中一项工作就是检查save选项所设置的保存条件是否已经满足。

服务器会遍历检查saveparams数组中所有的保存条件,只要有任意一个条件被满足,那么服务器就会执行BGSAVE命令。

执行完BGSAVE后,dirty计数器置0,更新lastsave属性。

RDB文件结构:

【Redis笔记】RDB持久化_字符串_09

 

(1)REDIS文件开头长度为5个字节,保存着“REDIS“ 5个字符,在载入时用来检查是否是RDB文件

(2)db_version长度为4个字节,是一个字符串表示的整数,记录了RDB文件的版本号。

(3)databases保存数据库以及数据库中的键值对。

(4)EOF常量的长度为1个字节,标志着RDB文件正文内容的结束。

(5)check_sum是一个8字节的无符号整数,保存着一个校验和,这个校验和是程序通过对前4个部分内容进行计算得出的,服务器在载入RDB文件时,会将载入数据所计算出的校验和与check_sum所记录的校验和进行对比,已经检查RDB文件是否有出错或者损坏的情况。

databases部分:

【Redis笔记】RDB持久化_数据库_10

 

1、SELECTDB常量长度为1个字节,当读入程序遇到这个值是,表明接下来读入的是一个数据库号码

2、db_number保存着一个数据库号码,根据号码大小不同,长度不同,可以是1字节,2字节或者5字节。当程序读入db_number部分之后,服务器会调用SELECT命令,根据读入的数据库号码进行数据库的切换,使得键值对可以载入到正确的数据库中。

3、key_value_pairs保存了数据库中的所有键值对数据,如果键值对带有过期时间,那么过期时间也会和键值对保存在一起。

 

key_value_pairs部分:

【Redis笔记】RDB持久化_redis_11

1、type记录了value的类型,长度为1字节

程序会根据TYPE的值来决定如何读入和解释value的数据。

2、key和value保存键值对的键对象和值对象:

(1)key总是一个字符串对象

(2)根据TYPE类型的不同,以及保存内容长度的不同,保存value的结构和长度不同。

3、带有过期键的键值对:

【Redis笔记】RDB持久化_服务器_12

 

【Redis笔记】RDB持久化_字符串_13

 

不同类型的值对象在RDB文件中保存结构:

1、字符串对象

(1)如果字符串对象的编码是REDIS_ENCODING_INT,说明对象中保存的是长度不超过32位的整数。

【Redis笔记】RDB持久化_数据库_14

 

  (2)如果字符串对象的编码是REDIS_ENCODING_RAW,说明对象保存的是一个字符串值。

如果字符串的长度小于等于20个字节,那么这个字符串会直接原样保存。

【Redis笔记】RDB持久化_缓存_15

如果字符串长度大于20字节,那么这个字符串会被压缩后再保存。

【Redis笔记】RDB持久化_缓存_16

2、列表对象

如果TYPE的值为REDIS_RDB_TYPE_LIST,那么value保存的就是一个列表对象

list_length记录列表长度

item是列表的项,每个列表项都是一个字符串,程序会以处理字符串对象的方式来保存和读入列表项。

【Redis笔记】RDB持久化_数据库_17


3、集合对象

如果TYPE的值为REDIS_RDB_TYPE_SET,那么value保存的就是一个字典实现的集合对象。

set_size集合大小

elem是集合中元素,每个元素都是一个字符串,程序会以处理字符串对象的方式来保存和读入集合元素。

【Redis笔记】RDB持久化_数据库_18

 

4、哈希表对象

如果TYPE的值为REDIS_RDB_TYPE_HASH,那么value保存的就是一个字典实现的哈希对象。

hash_size记录键值对的个数

key_pair_value代表哈希表中键值对,键值对的键的值都是字符串对象。

结构中的每个键值对都以紧挨着的方式排列在一起。

【Redis笔记】RDB持久化_字符串_19

 

【Redis笔记】RDB持久化_字符串_20

 

5、有序集合对象

如果TYPE的值是REDIS_RDB_TYPE_ZSE,那么value保存的值就是跳跃表实现的有序集合对象。

sorted_set_size记录有序集合中的元素。

每个元素又分为成员和分值。成员是一个字符串对象,分值是double类型的浮点数,存储时转换为字符串。

有序集合中的每个元素的成员和分值紧挨着排序。

【Redis笔记】RDB持久化_缓存_21

【Redis笔记】RDB持久化_数据库_22

 

 

6、整数集合对象

将整数集合转换为字符串对象保存。

7、ZIPLIST编码的列表哈希表或者有序集合

将压缩列表转换成一个字符串对象,将转换所得的字符串对象保存到RDB文件中。