在redis服务器启动之后,内部定期执行执行一个时间事件函数serverCron,这个函数默认每隔100毫秒就会执行一次,该函数用于对正在运行的服务器进行维护,其中一项工作就是检查save选项设置的保存条件是否满足,如果满足,就执行bgsave命令。
伪代码如下:
def serverCron():
# ... # 遍历所有保存条件 for saveparam in server.saveparams:
#计算具体上次执行保存操作有多少秒 save_interval = unixtime_now() - server.lastsave
# 如果数据库状态的修改次数超过条件所设置的次数 # 并且距离上次保存的时间超过条件所设置的时间 # 那么执行保存操作
if server.dirty >= saveparam.changes and save_interval > saveparam.seconds:
BGSAVE()
# ...
以上就是redis服务器根据save选项所设置的保存条件,自动执行bgsave命令,进行间隔性数据保存的实现原理。
二,AOF持久化RDB持久化是通过保存数据库中的键值对来记录数据库状态,而AOF持久化则是通过保存Redis服务器所执行的写命令来记录数据状态(如:set key "hello world" 以RDB持久化方式,文件内容为key:hello world,以AOF持久化方式,文件内容为set key "hello world")。
接下来,我们来看看AOF持久化的实现原理以及减小AOF文件体积的AOF文件重写实现原理。
1.AOF持久化实现这里,我们先说说AOF持久化操作,写入文件的操作并不是单单将命令写入,如set key "hello world",而是将命令按照某种格式进行写入,至于为什么要这样做,后面我们再说。写入文件的内容以某个格式,我们称为协议格式。如上面的命令,则写入文件的如下:*2\r\n$3\r\nset\r\n$3\r\nkey\r\n$5\r\nhello\r\n$5\r\nworld
AOF持久化分为三个步骤:命令追加,文件写入,文件同步
命令追加
当AOF持久化功能处于打开状态,服务器在执行完一个写命令之后,会以协议格式的形式将被执行的命令追加到服务器aof_buf缓冲区,至于为什么要写入,后面介绍。
struct redisServer{
sds aof_buf; // 写入缓冲区
};
文件写入与同步
Redis是单线程架构,也就是说redis服务进程处于一个事件循环中,这个事件循环负责接受来自客户端的命令,以及向客户端发送命令,而时间事件则负责想serverCron函数这样需要定时运行的函数。
因为服务器在处理文件事件时,可能会执行写命令,使得一些内容被追加到aof_buf缓冲区里面,所以在服务器每次结束一个事件循环,它都会调用flushAppendOnlyFile函数,考虑是否需要将aof_bug缓冲区中的内容写入和保存到AOF文件里面,这个过程可用如下代码描述:
def event_loop():
while True:
# 处理文件事件,接收命令请求以及发送命令回复 # 处理命令请求时可能会有新内容被追加到aof_buf缓冲区中 processFileEvents()
# 处理函时间事件 processTimeEvents()
# 考虑是否将aof_buf中的内容写入和保存到AOF文件里面
flushAppendOnlyFile()
而flushAppendOnlyFile函数行为由服务器配置redis.conf中的appendsync选项的值来决定。
appendsync=always/everysec(默认)/no
2.AOF文件的载入与数据还原因为AOF文件里面包含了重键数据库状态所需的所有写命令,所以服务器只要读入并重新执行一遍AOF文件里面保存的写命令,就可以还原服务器关闭之前的数据库状态。
具体还原过程: