redis源码分析(7)——rdb

RDB是redis的另一种持久化方式,相当于是定时快照,也用于主从同步中快照+redo log。redis在进行RDB时,不需要加锁,这是通过利用父子进程共享同一份内存完成的。在父进程fork子进程之后,父子以copy-on-write方式共享同一份物理内存,当两个进程写内存时,才会按照内存页复制内存。这就需要保证在RDB时,最坏情况下需要保证有2倍的内存空间用于父子进程使用(redis使用时占用1G,那么就要保证系统有2G的内存,否则可能会出现使用swap的情况)。因为copy-on-write,所以需要避免不必要的内存拷贝。子进程中基本上只需要读内存,而父进程响应客户端请求,就需要修改内存,为了减少内存修改,父进程会暂停keyspace对应的hash表的rehash(rehash会有大量拷贝,要在不同的桶之间拷贝数据)。下面看一下RDB相关内容。

1. RDB文件格式

RDB文件格式比较简单,可以看做是一条条指令序列,每条指令的组成:

|-----------------------|----------------------------------|

| OP code: 1Byte  |       Instruction: nBytes    |

|-----------------------|----------------------------------|

在加载RDB时,就是对这个指令序列进行解析。所有的OP code包括:

REDIS_RDB_OPCODE_EXPIRETIME_MS: ms级的过期时间

REDIS_RDB_OPCODE_EXPIRETIME:秒级的过期时间

REDIS_RDB_OPCODE_SELECTDB:用于select db命令

REDIS_RDB_OPCODE_EOF:RDB文件结尾

OP code还包括所有的数据类型(REDIS_RDB_TYPE_LIST, REDIS_RDB_TYPE_SET等),用于指定后续kv对中,value的类型。

RDB文件的前5个字节是magic number,用于表示文件是RDB文件。接下来的4个字节是版本号,在加载RDB时,会根据RDB的版本号和redis的版本号比较,查看是否可以处理该版本的RDB。然后,是一条条指令序列,最后以EOF结尾。

2. RDB dump

首先看一下dump的时机,主要分为3块:

1)save命令:客户端发送save命令,redis实例阻塞执行dump。在saveCommand函数中。

2)bgsave命令:dump任务由子进程完成,主进程可以继续服务请求。在bgsaveCommand函数中。

3)被动触发:redis变更次数或者dump的间隔超过阈值。在serverCron中,检测并触发。

4)主从同步触发:在不能实现partial sync时,master需要将rdb传输给slave。在syncCommand函数中。

下面看一下rdb dump的具体过程,这是由rdbSave函数完成的。

    // <MM>
    // 创建并打开临时rdb文件
    // </MM>
    snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
    fp = fopen(tmpfile,"w");
    if (!fp) {
        redisLog(REDIS_WARNING, "Failed opening .rdb for saving: %s",
            strerror(errno));
        return REDIS_ERR;
    }

    rioInitWithFile(&rdb,fp);
    if (server.rdb_checksum)
        rdb.update_cksum = rioGenericUpdateChecksum;
创建并打开临时文件,这是为了保证rdb的数据完整性,只有在dump成功后,才会替换原文件。然后是初始化rio,用于输出。

    // <MM>
    // 写入magic number,format:
    // 9bit: REDIS[RDB_VERSION]
    // </MM>
    snprintf(magic,sizeof(magic),"REDIS%04d",REDIS_RDB_VERSION);
    if (rdbWriteRaw(&rdb,magic,9) == -1) goto werr;
写入magic number以及版本号。

接下来是一个循环,用于对每个redis DB遍历,并生成对应的内容。

    for (j = 0; j < server.dbnum; j++) {
        // dump该DB
    }
看下每个DB的dump过程,实际上就是遍历并输出每个Key-Value对。

        redisDb *db = server.db+j;
        dict *d = db->dict;
        if (dictSize(d) 
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值