RDB持久化②自动间隔性保存

197 阅读2分钟

这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

RDB持久化②自动间隔性保存

通过设置服务器配置的save选项,让服务器每隔一段时间自动执行一次BGSAVE命令,save选项可以设置多个保存条件,只要任意一个条件被满足,服务器就会执行BGSAVE命令。

通过save选项的设置,服务器保存在saveparams属性中,saveparams是个数组,每个saveparam结构都保存了一个save选项设置的保存条件

struct saveparam {
    time_t seconds;
    int changes;
};

服务器有一个dirty计数器和lastsave属性,dirty计数器用来记录距离上一次成功执行save命令或者BGSAVE命令后服务器对数据库进行了多少次修改,lastsave记录服务器中上一次成功执行save命令或者BGSAVE命令的时间。

当服务器成功执行数据库修改命令后,程序对dirty计数器进行更新,命令修改多少次数据库,dirty计数器的值就增加多少

redis的服务器周期性操作函数serverCron默认每隔100毫秒执行一次,用于维护正在运行的服务器,检查是否满足save保存的条件,如果满足,执行BGSAVE命令。

/* Check if a background saving or AOF rewrite in progress terminated. */
// 如果 BGSAVE 或者 BGREWRITEAOF 正在进行
// 那么检查它们是否已经执行完毕
if (server.rdb_child_pid != -1 || server.aof_child_pid != -1) {
    int statloc;
    pid_t pid;

    if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) {
        int exitcode = WEXITSTATUS(statloc);
        int bysignal = 0;
        
        if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc);

        if (pid == server.rdb_child_pid) {
            backgroundSaveDoneHandler(exitcode,bysignal);
        } else if (pid == server.aof_child_pid) {
            backgroundRewriteDoneHandler(exitcode,bysignal);
        } else {
            redisLog(REDIS_WARNING,
                "Warning, detected child with unmatched pid: %ld",
                (long)pid);
        }
        // 如果 BGSAVE 和 BGREWRITEAOF 都已经完成,那么重新开始 REHASH
        updateDictResizePolicy();
    }
} else {
    /* If there is not a background saving/rewrite in progress check if
     * we have to save/rewrite now */
     // 如果有需要,开始 RDB 文件的保存
     for (j = 0; j < server.saveparamslen; j++) {
        struct saveparam *sp = server.saveparams+j;

        if (server.dirty >= sp->changes &&
            server.unixtime-server.lastsave > sp->seconds) {
            redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
                sp->changes, sp->seconds);
            rdbSaveBackground(server.rdb_filename);
            break;
        }
     }

     /* Trigger an AOF rewrite if needed */
     // 如果有需要,开始 AOF 文件重写
     if (server.rdb_child_pid == -1 &&
         server.aof_child_pid == -1 &&
         server.aof_rewrite_perc &&
         server.aof_current_size > server.aof_rewrite_min_size)
     {
        long long base = server.aof_rewrite_base_size ?
                        server.aof_rewrite_base_size : 1;
        long long growth = (server.aof_current_size*100/base) - 100;
        if (growth >= server.aof_rewrite_perc) {
            redisLog(REDIS_NOTICE,"Starting automatic rewriting of AOF on %lld%% growth",growth);
            rewriteAppendOnlyFileBackground();
        }
     }
}

这就是BGSAVE的实现原理