参考:《Redis设计与实现》
文章目录
1、RDB文件左右
数据库状态:
服务器中非空数据库以及它们的键值对。
数据库状态磁盘化:
Redis是 内存数据库,它将自己的数据库状态存在内存中,所以如果不想办法将存储在内存中的数据库状态保存到磁盘,一旦进程退出,服务器中的数据库状态也会消失不见。
为了解决上述问题,Redis提供了RDB持久化功能,这个功能可以将Redis在内存中的数据库状态保存到磁盘,避免数据的意外丢失
RDB持久化:
可以手动触发,也可以根据服务器配置选项周期性执行,将某个时间点上的数据库状态保存到RDB文件中。
RDB文件:
是一个经过压缩的二进制文件,通过改文件可以还原生成RDB文件时的数据库状态。RDB文件是保存在磁盘上的,所以即使Redis服务器进程退出,只要RDB文件存在,Redis服务器就可以还原数据库状态。
2、RDB文件的创建和载入
有两个命令可以生成RDB文件,分别是SAVE和BGSAVE。
1、SAVE-RDB文件创建
SAVE命令会阻塞Redis进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不会处理任何命令请求。
SAVE的代码处理实现:
def SAVE():
//创建RDB文件
rdbSave()
2、BGSAVE-RDB文件创建
BGSAVE命令会派生出一个子进程,通过子进程创建RDB文件,服务器进程(父进程)继续处理命令请求。
BGSAVE的代码处理实现:
def BGSAVE():
pid = fork() //fork子进程
if pid == 0 :
rdbSave() //RDB文件保存
signal_parent() //给父进程发送信号
else if pid > 0:
handle_request_and_wait_signal() //处理客户端请求,并轮训等待子进程的信号
else:
handle_fork_error() //处理错误的情况
BGSAVE命令执行期间其他命令的可执行性
- 如果客户端发送SAVE命令会被服务器拒绝,原因是:避免父进程和子进程同时执行两个rdbSave调用,产生竞争关系。
- 如果客户端发送BGSAVE命令会被服务器拒绝,原因是:两个BGSAVE命令也可能产生竞争关系。
- 如果客户端发送BGREWRITEAOF(AOF)命令,会被延迟到BGSAVE命令执行结束之后执行,原因:虽然两个子进程之间不冲突,但是为了避免两个子进程同时执行大量的磁盘写入操作。
- 如果服务器正在执行BGREWRITEAOF命令,客户端发送BGSAVE命令会被服务器拒绝。
3、RDB文件载入
RDB文件的载入是在服务器启动时自动执行的,Redis并没有专门用于载入RDB文件的命令,只要redis服务器启动时检测到RDB文件,就会自动载入。
因为AOF文件的更新频率比RDB文件更高,所以如果服务器开启AOF持久化功能,会优先通过AOF文件来还原数据库状态。所以整个的执行过程如下:
服务器在载入RDB文件的过程中,会一直处于阻塞状态,直到载入工作完成为止。
3、RDB文件自动间隔性保存
1、save选项配置
Redis允许用户通过设置服务器配置save选项,服务器隔一段时间之后会执行一次BGSAVE命令。
save选项对应的代码结构:
{
struct saveparam *saveparams //保存对应配置的数组
struct saveparam{
time_t seconds //秒数
int changes //修改数
}
}
save选项默认值和意义:
save 900 1
save 300 10
save 60 10000
##含义
#第一行:服务器在900秒之内至少进行了1次修改
#第二行:服务器在300秒之内至少进行了10次修改
#第三行:服务器在60秒内至少进行了10000次修改
#只要满足其中一个条件就会触发BGSAVE操作
2、具体实现
Redis服务器通过dirty计数器(操作了多少个数据库数字就加上多少的值)和lastsave最后一次保存时间,来实现是否执行BGSAVE命令的判断:
具体的数据结构如下:
struct redisServer{
long long dirty //dirty计数器
time_t lastsave //上一次进行保存的时间信息
}
Redis 的服务器周期性函数serverCron默认每隔100毫秒执行一次,通过检查save选项的条件是否满足,来判断是否进行BGSAVE函数的执行。
4、RDB文件结构
RDB文件结构如下,键值对的value存储可能采用压缩,存储的类型也会导致value的多样化,可参考原书:
地址:RDB文件结构图解