Redis源码剖析之持久化(2)

  在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文件里面保存的写命令,就可以还原服务器关闭之前的数据库状态。

  具体还原过程:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/0d33737369a96d387949bb8541a74607.html