数据库状态:将服务器中的非空数据库以及键值对统称为数据库状态
为什么要RDB持久化?
因为redis是内存数据库,将自己的数据库状态储存在内存里面,如果不把内存中的数据库状态保存到磁盘里面,那么一旦服务器退出,服务器中的 数据库状态也会消失不见。
RDB文件的创建:
SAVE命令:阻塞Redis服务器进程,直到RDB文件创建完毕为止。
当SAVE命令正在执行时,客户端发送的所有命令都会被拒绝。
BGSAVE命令:派生出一个子进程,然后由子进程负责创建RDB文件,父进程继续处理命令请求。
注意:
(1)BGSAVE命令执行期间,客户端发送的SAVE命令会被服务器拒绝。
原因:为了避免父进程和子进程同时执行两个rdbSave调用,防止产生竞争条件
(2)BGREWRITEAOF和BGSAVE不能同时执行。
原因:两个子进程都同时执行大量的磁盘写入操作,考虑到性能。
RDB文件的载入:
Redis服务器在启动时自动载入RDB文件,所以Redis并没有专门载入RDB文件的命令,只要Redis服务器在启动时检测到RDB文件的存在,就会自动载入RDB文件。
注意:
(1)如果服务器开启了AOF持久功能,那么服务器会优先使用AOF来还原数据库状态。
(2)服务器在载入RDB文件期间,会一直处于阻塞状态,直到载入工作完成为止。
BGSAVE的自动间隔性保存:
Redis运行用户通过设置服务器配置的save选项,让服务器每隔一段时间自动执行一次BGSAVE命令。
用户可以通过save选项设置多个保存条件,但只要其中任意一个条件被满足,服务器就会执行BGSAVE命令。
原理:
1、save选项保存在redisServer的saveparams数组中
2
(1)服务器状态维护一个dirty计数器,记录距离上一次成功执行SAVE命令或者BGSAVE命令之后,服务器对数据库状态(服务器中的所有数据库)进行修改的次数(包括写入,删除,更新等操作)
(2)服务器状态维护一个lastsave属性,记录服务器上一次成功执行SAVE命令或者BGSAVE命令的时间
3、定时检查保存条件是否满足:
Redis服务器周期性操作函数serverCron默认每隔100毫秒就会执行一次,该函数用于对正在运行的服务器进行维护,它的其中一项工作就是检查save选项所设置的保存条件是否已经满足。
服务器会遍历检查saveparams数组中所有的保存条件,只要有任意一个条件被满足,那么服务器就会执行BGSAVE命令。
执行完BGSAVE后,dirty计数器置0,更新lastsave属性。
RDB文件结构:
(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部分:
1、SELECTDB常量长度为1个字节,当读入程序遇到这个值是,表明接下来读入的是一个数据库号码
2、db_number保存着一个数据库号码,根据号码大小不同,长度不同,可以是1字节,2字节或者5字节。当程序读入db_number部分之后,服务器会调用SELECT命令,根据读入的数据库号码进行数据库的切换,使得键值对可以载入到正确的数据库中。
3、key_value_pairs保存了数据库中的所有键值对数据,如果键值对带有过期时间,那么过期时间也会和键值对保存在一起。
key_value_pairs部分:
1、type记录了value的类型,长度为1字节
程序会根据TYPE的值来决定如何读入和解释value的数据。
2、key和value保存键值对的键对象和值对象:
(1)key总是一个字符串对象
(2)根据TYPE类型的不同,以及保存内容长度的不同,保存value的结构和长度不同。
3、带有过期键的键值对:
不同类型的值对象在RDB文件中保存结构:
1、字符串对象
(1)如果字符串对象的编码是REDIS_ENCODING_INT,说明对象中保存的是长度不超过32位的整数。
(2)如果字符串对象的编码是REDIS_ENCODING_RAW,说明对象保存的是一个字符串值。
如果字符串的长度小于等于20个字节,那么这个字符串会直接原样保存。
如果字符串长度大于20字节,那么这个字符串会被压缩后再保存。
2、列表对象
如果TYPE的值为REDIS_RDB_TYPE_LIST,那么value保存的就是一个列表对象
list_length记录列表长度
item是列表的项,每个列表项都是一个字符串,程序会以处理字符串对象的方式来保存和读入列表项。
3、集合对象
如果TYPE的值为REDIS_RDB_TYPE_SET,那么value保存的就是一个字典实现的集合对象。
set_size集合大小
elem是集合中元素,每个元素都是一个字符串,程序会以处理字符串对象的方式来保存和读入集合元素。
4、哈希表对象
如果TYPE的值为REDIS_RDB_TYPE_HASH,那么value保存的就是一个字典实现的哈希对象。
hash_size记录键值对的个数
key_pair_value代表哈希表中键值对,键值对的键的值都是字符串对象。
结构中的每个键值对都以紧挨着的方式排列在一起。
5、有序集合对象
如果TYPE的值是REDIS_RDB_TYPE_ZSE,那么value保存的值就是跳跃表实现的有序集合对象。
sorted_set_size记录有序集合中的元素。
每个元素又分为成员和分值。成员是一个字符串对象,分值是double类型的浮点数,存储时转换为字符串。
有序集合中的每个元素的成员和分值紧挨着排序。
6、整数集合对象
将整数集合转换为字符串对象保存。
7、ZIPLIST编码的列表哈希表或者有序集合
将压缩列表转换成一个字符串对象,将转换所得的字符串对象保存到RDB文件中。