《Redis设计与实现》读书笔记(十四)
——Redis RDB文件创建、载入与自动保存原理
(原创内容,转载请注明来源,谢谢)
一、概述
redis是一个键值对服务器,服务器中包含若干个非空数据库,数据库中包含若干个非空键值对。将非空数据库及其键值对统称为数据库状态。如下图所示:
由于redis是内存型数据库,必须要将数据保存到磁盘,才能保证数据不丢失。RDB持久化就是将数据库保存到磁盘的方式之一(另一种叫做AOF)。rdb可以手动执行,也可以根据服务器的配置定期执行,持久化后会将整个数据库备份成一个二进制文件存在磁盘,而还原则是将该二进制文件重新转成数据库存在内存。
二、rdb文件创建与载入
1、创建
有两个命令可以手动生成rdb文件——save和bgsave。
save会阻塞redis进程,直到save命令执行完毕;bgsave会创建一个子进程,由子进程处理rdb任务,父进程继续处理客户端请求。
保存rdb文件的过程,如果是bgsave命令,会先检查是否当前有还未完成的子进程,如果有的话会等待,待当前子进程完成任务后,才会开始执行bgsave。
1)save
由于save命令是阻塞的,因此当执行save命令期间,服务器会拒绝其他命令的请求,直到save命令执行完毕。
2)bgsave
bgsave是通过子进程进行创建rdb文件的工作,因此bgsave执行期间,服务器可以正常处理大部分的redis客户端请求,除了以下内容有所不同:
save:redis子进程在处理bgsave命令期间,会拒绝客户端发来的save命令,目的是为了避免父进程和子进程同时在创建rdb文件,也避免产生竞争条件。
bgsave:同样会被拒绝,同save。
bgwriteaof:bgsave执行期间,bgwriteaof命令会被延迟到bgsave命令执行完毕后才会执行; bgwriteaof执行期间,bgsave命令会直接被服务器拒绝。这两个命令都是由子进程进行,拒绝同时进行是为了考虑性能,并发处理两个大量写入磁盘的子进程是应当被避免的。
2、载入
载入比较简单,redis没有专门载入rdb文件的命令,每当redis服务器开启的时候,就会检查,如果存在rdb文件则自动载入。
但是由于aof的执行频率比rdb高,所以如果同时存在aof文件,则会载入aof文件,只有aof功能除以关闭状态,才会载入rdb文件。
redis服务器载入rdb文件期间,会一直处于阻塞状态,直到载入完毕。
如下所示:
三、自动保存
由于bgsave命令具有非阻塞特性,因此redis服务器运行用户通过配置文件中的save选项,让数据库每隔一段时间执行一次bgsave命令。save选项保存的是执行bgsave命令的条件,可以保存多个,只要有一个条件满足,服务器就执行bgsave命令。
save设置的示例如下:
save900 1
save300 10
save60 10000
表示的含义是,下列情况发生一种就执行bgsave:redis服务器900秒内至少执行1次修改;300秒内至少执行10次修改;60秒内至少执行10000次修改。
上述的save条件也是redis配置save的默认值,即没有特意指定save条件,则都会按上述设置执行bgsave。
1、保存结构
服务器启动时,会读取save条件,并写入其redisServer结构的saveparams属性中。
structredisServer{
//…其他属性
struct saveparam *saveparams;
}
由上可知,saveparams是一个数组,由saveparam结构元素组成。
structsaveparam{
time_t seconds;
int changes;
}
由上结构可知,saveparam保存了时间和改变次数,即对应上述每一行save后面跟的两个参数。
上面默认的save条件配置的存储方式如下图所示:
2、dirty计数器和lastsave属性
dirty计数器记录距离上一次成功执行save或bgsave命令后,服务器对其中所有数据库进行的修改(增删改)的总次数。lastsave属性是一个UNIX时间戳,记录服务器上一次成功执行save或bgsave的时间。
structredisServer{
long long dirty;
time_t lastsave;
}
结构如下图所示:
每执行一次修改,dirty值就加1,如果是批量修改命令如sadd等,一次修改多个值,则修改几个dirty的值就加多少。
这两个属性分别是用于比较save条件的两个参数——修改次数和时间,是否匹配,以判定是否要执行bgsave命令。
3、检查是否满足保存条件
redis服务器的周期性函数serverCron,默认每隔100毫秒执行一次,用来维护运行中的服务器,其中一项工作就是检查save条件,满足的话就执行bgsave命令。
其判断方式是,循环save配置,分别比较save每一条配置的修改次数与redisServer结构中的dirty属性值、当前时间减去lastsave属性判断经过的时间,有一个符合则执行bgsave命令。
总体结构体如下:
上述情况来看,dirty是123,则当时间经过300秒,就会自动执行bgsave。
执行完成后,dirty属性值清0,并且lastsave属性会被重新写入完成bgsave时间点的unix时间戳。
——written by linhxx 2017.09.04