JavaJava 程序员

Redis 源码分析——RBD 持久化,面试官被我讲懵了

2022-03-10  本文已影响0人  马小莫QAQ

原理

Redis 提供了 RDB 持久化功能,这个功能可以将 Redis 在内存中的数据库状态保存到磁盘里面,避免数据意外丢失。

触发时机:手动触发、自动触发。

配置读取

redis.conf中 rdb 相关的配置如下:

rdbcompression 
  rdb 文件为了解约空间,支持压缩,要开启该功能
  需要在配置文件中设置参数 rdbcompression (默认开启的),
  当前开启参数后 redis 利用 lz 算法对
stop-writes-on-bgsave-error
  为了保证数据的一致性,redis 默认开启该选项
dbfilename
  rdb 文件名,默认 dump.rdb
save <seconds> <changes>
  指明 rdb 触发机制,表示 seconds 秒改变 changes 触发

mac 系统 brew 安装 rdb 文件位置:

rdb 文件查看

od -c dump.rdb

➜  redis od -c dump.rdb
0000000    R   E   D   I   S   0   0   0   9 372  \t   r   e   d   i   s
0000020    -   v   e   r 005   6   .   0   .   9 372  \n   r   e   d   i
0000040    s   -   b   i   t   s 300   @ 372 005   c   t   i   m   e 313
0000060  313   x   '   b 372  \b   u   s   e   d   -   m   e   m 302 300
0000100    B 020  \0 372  \f   a   o   f   -   p   r   e   a   m   b   l
0000120    e 300  \0 376  \0 373 001  \0 370   "  \0 003   m   s   g 300
0000140  001 377   9   3 235 231   R 251   \   N                        
0000152

手动触发

Redis 可以执行 SAVE、BGSAVE进行手动触发 RDB 持久化操作。

RDB 文件的创建是由 rdb.c/rdbSave函数完成,具体代码如下:

/* Save the DB on disk. Return C_ERR on error, C_OK on success. */
int rdbSave(char *filename, rdbSaveInfo *rsi) {
    char tmpfile[256];
    char cwd[MAXPATHLEN]; /* Current working dir path for error messages. */
    FILE *fp = NULL;
    rio rdb;
    int error = 0;

    snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
    fp = fopen(tmpfile,"w");
    if (!fp) {
        char *cwdp = getcwd(cwd,MAXPATHLEN);
        serverLog(LL_WARNING,
            "Failed opening the RDB file %s (in server root dir %s) "
            "for saving: %s",
            filename,
            cwdp ? cwdp : "unknown",
            strerror(errno));
        return C_ERR;
    }

    rioInitWithFile(&rdb,fp);
    startSaving(RDBFLAGS_NONE);

    if (server.rdb_save_incremental_fsync)
        rioSetAutoSync(&rdb,REDIS_AUTOSYNC_BYTES);

    if (rdbSaveRio(&rdb,&error,RDBFLAGS_NONE,rsi) == C_ERR) {
        errno = error;
        goto werr;
    }

    /* Make sure data will not remain on the OS's output buffers */
    if (fflush(fp)) goto werr;
    if (fsync(fileno(fp))) goto werr;
    if (fclose(fp)) { fp = NULL; goto werr; }
    fp = NULL;

    /* Use RENAME to make sure the DB file is changed atomically only
     * if the generate DB file is ok. */
    if (rename(tmpfile,filename) == -1) {
        char *cwdp = getcwd(cwd,MAXPATHLEN);
        serverLog(LL_WARNING,
            "Error moving temp DB file %s on the final "
            "destination %s (in server root dir %s): %s",
            tmpfile,
            filename,
            cwdp ? cwdp : "unknown",
            strerror(errno));
        unlink(tmpfile);
        stopSaving(0);
        return C_ERR;
    }

    serverLog(LL_NOTICE,"DB saved on disk");
    server.dirty = 0;
    server.lastsave = time(NULL);
    server.lastbgsave_status = C_OK;
    stopSaving(1);
    return C_OK;

// 出错处理
werr:
    serverLog(LL_WARNING,"Write error saving DB on disk: %s", strerror(errno));
    if (fp) fclose(fp);
    unlink(tmpfile);
    stopSaving(0);
    return C_ERR;
}

自动触发

Redis 支持用户通过设置服务器配置save 选项(在 redis.conf 中) ,让服务服务器每间隔一段事件自动执行一次 BGSAVE命令。

默认配置如下所示:

save 900 1
save 300 10
save 60 10000

那么只要满足以下三个条件中的任意一个,BGSAVE命令就会被执行:

服务器中会根据 save 选项设置的保存条件,设置服务器状态的 redisServer 结构的 saveparams 属性

struct redisServer {

    // 记录保存条件
    struct saveparam *saveparams;   /* Save points array for RDB */
}

// saveparam 定义
struct saveparam {
    time_t seconds;
    int changes;
};

总结

1、Redis 中提供了手动,自动两种方式来持久化数据,其实也是在性能和可靠性的折中处理。

2、自动持久化除了 saveparams数组之外,服务器状态还维持着一个dirty计数器,以及一个lastsave属性:

struct redisServer {

    // 修改计数器
    long long dirty;                /* Changes to DB from the last save */

    // 上次保存时间
    time_t lastsave;                /* Unix time of last successful save */
}

3、Redis 的服务器周期性操作函数 serverCron 默认每隔 100 毫秒就会执行一次,该函数用于对正在运行的服务器进行维护,它的其中一项工作就是检查 save 选项所设置的保存条件是否已经满足,如果满足的话,就执行 BGSAVE 命令。

RDB 结构图

图例:

  1. 粉色框中字段为固定字符串
  2. 绿色框中字段为整数
  3. 紫色框中是拓展的数据
  4. 黄色框中value类型是一个枚举的常量
  5. 蓝色框中是实际存储的键值对数据

作者:心城以北
链接:https://juejin.cn/post/7072757775247343623
来源:稀土掘金

上一篇下一篇

猜你喜欢

热点阅读