一、间隔性保存
1.1 配置
在上一节中知道了SAVE和BGSAVE两个命令的区别:SAVE命令由服务器进程执行保存工作,BGSAVE命令由子进程执行保存工作,所以SAVE
命令会阻塞服务器,BGSAVE
命令则不会。
因为BGSAVE命令可以在不阻塞服务器进程的情况下执行,所以Redis允许用户通过设置服务器配置的save选项,让服务器每隔一段时间自动执行依次BGSAVE命令。
通过save选项设置多个保存条件,但是只要其中一个条件被满足,服务器就会执行BGSAVE命令。
例如,想服务器中提供了三种save选项配置:
- save 900 1 :服务器在900秒之内,对数据库进行了至少1次修改
- save 300 10 :服务器在300秒内,对数据库进行了至少10次修改
- save 60 10000 :服务器在60秒内,对数据库进行了至少10000次修改
因为只要满足以上三个条件中的任意一个,BGSAVE命令就会被执行
1.2 dirty计数器和lastsave属性
在Redis服务器中维持着一个dirty计数器以及一个lastsave属性:
- dirty:该计数器记录距离上次成功执行SAVE命令或者BGSAVE命令之后,服务器对数据库状态进行了多少次修改(包括写入、删除、更新等操作)。
- lastsave:该属性是一个UNIX时间戳,记录了服务器上一次成功执行SAVE命令或者BGSAVE命令的时间。
struct redisServer{
//....
//修改计数器
long long dirty;
//上一次执行的保存时间
time_t lastsave;
//....
}
当服务器成功执行了一个数据库修改命令之后(例如修改数据、删除数据、更新数据等),程序就会对dirty计数器进行更新;命令修改了多少次数据库,dirty就增加多少。
例如:对修改一个字符串键值
redis>SET message "hello"
OK
那么程序就会将dirty计数器的值增加1.
如果我们向一个集合中增加三个新元素:
redis>SADD database Redis MongoDB MariaDB
(integer) 3
那么程序会将dirty计数器的值增加3.
上图中展示了服务器状态中的dirty计数器和lastsave属性:
- dirty计数器的值为100,表示服务器在上次保存之后,对数据库状态修改了100次
- lastsave属性记录了服务器上次执行保存操作的时间戳
二、RDB文件结构
RDB文件中保存的时二进制数据,而不是C字符串。
下图展示一个完整的RDB文件所包含的各个部分:
- REDIS:REDIS这部分的长度为5字节,保存着REDIS五个字节,通过这五个字节,程序可以在载入文件时,快速检查所载入的文件是否时RDB文件。
- db_version:这部分的长度为4字节,它的值是一个字符串表示的整数,这个整数记录了RDB文件的版本号。
- databases:这部分包含着任意多个数据库,以及各个数据库中的键值对数据,如果数据库中的数据为空,则该部分也为空。
- EOF:EOF长度为1字节,这个常量标志着RDB文件正文内容的结束,当读入程序遇到这个值的时候,服务器就知道所有数据库中的所有键值对都已经载入完毕了。
- check_num:这是一个8个字节的无符号整数,保存着一个校验和,这个校验和时程序通过对REDIS、db_version、databases、EOF四部门的内容进行计算得出的。服务器在载入RDB文件时,会将载入数据所计算出的校验和与check_num所记录的校验和进行对比,以此来检查RDB文件是否有出错或者损坏的情况。