Redis 设计与实现(第九章) -- 持久化RBD

Posted qiezijiajia

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis 设计与实现(第九章) -- 持久化RBD相关的知识,希望对你有一定的参考价值。

概述


Redis为内存数据库,即所有的键值对信息保存在内存中,那么一旦服务器出现问题重启,内存中的数据就会没有了。所以Redis需要实现持久化,将内存中的数据持久化到硬盘,在重新启动后,又将硬盘中的数据加载到内存中。

RDB文件生成与载入

  • 有两个命令可用于生成RDB文件,save和bgsave:

Save:save命令会阻断服务器进程,直到RDB文件生成,在阻塞期间,Redis服务器不会出现任何请求。

bgsave:bgsave命令会派生出一个子进程,然后由子进程来创建RDB文件,服务器进程继续出现请求命令。

  • Redis中RDB文件载入没有专门的命令,只要在redis服务器重启的过程中,检测到rdb文件的存在就会自动加载。(这里先忽略AOF的情况,因为在AOF开启的情况下,服务器会优先加载AOF文件,因为AOF的更新频率通常比较RDB的高)
  • 命令执行的服务器状态
    • SAVE命令会阻塞服务器的请求,也就是保存期间,如果服务器有新的请求过来,不会去处理请求直到RDB文件生成;
    • BGSAVE命令,会fork一个子进程出来,所以服务器能够处理其他请求命令;
    • 如果在执行BGSAVE命令时,客户端再次执行SAVE,BGSAVE或BGREWRITEAOF呢?
      • 不能同时执行,避免竞争条件发生。
    • 在RDB文件载入时,所有请求均处于阻塞状态。

我们不可能每次手动去调用命令来持久化,Redis自身肯定是有一套策略的,什么时候进行持久化。

默认情况下,redis在下列条件满足其一,BGSAVE命令就会执行(可通过配置修改):

  • 服务器在900秒内对数据库进行了至少一次修改;
  • 服务器在300秒内对数据库进行了至少10次修改;
  • 服务器在60秒内对数据库进行了至少10000次修改;

可以看一下数据结构:
在redisServer的数据结构中,有个属性用于记录保存条件的修改:

/* RDB persistence */
    long long dirty;                /* Changes to DB from the last save */
    long long dirty_before_bgsave;  /* Used to restore dirty on failed BGSAVE */
    pid_t rdb_child_pid;            /* PID of RDB saving child */
    struct saveparam *saveparams;   /* Save points array for RDB */

再看下saveparam的数据结构:

struct saveparam {
    time_t seconds;  //时间
    int changes;  //修改数
};

此外,redisServer中还有两个属性dirty和lastsave:

/* RDB persistence */
    long long dirty;                /* Changes to DB from the last save,上次保存命令执行后,数据库的修改次数 */
    long long dirty_before_bgsave;  /* Used to restore dirty on failed BGSAVE */
    pid_t rdb_child_pid;            /* PID of RDB saving child */
    struct saveparam *saveparams;   /* Save points array for RDB */
    int saveparamslen;              /* Number of saving points */
    char *rdb_filename;             /* Name of RDB file */
    int rdb_compression;            /* Use compression in RDB? */
    int rdb_checksum;               /* Use RDB checksum? */
    time_t lastsave;                /* Unix time of last successful save ,上次成功保存的时间*/

RedisServer会定期执行serverCron(100ms一次),每次执行时,会检测之前默认的条件是否满足,如果满足条件则执行bgsave命令。程序会遍历saveparam中的数组,判断是否满足条件。

/* If there is not a background saving/rewrite in progress check if(之前会判断是否有AOF或BSAVE命令正在执行)
         * we have to save/rewrite now */
         for (j = 0; j < server.saveparamslen; j++) {
            struct saveparam *sp = server.saveparams+j;

            /* Save if we reached the given amount of changes,
             * the given amount of seconds, and if the latest bgsave was
             * successful or if, in case of an error, at least
             * REDIS_BGSAVE_RETRY_DELAY seconds already elapsed. */
            if (server.dirty >= sp->changes &&
                server.unixtime-server.lastsave > sp->seconds &&
                (server.unixtime-server.lastbgsave_try >
                 REDIS_BGSAVE_RETRY_DELAY ||
                 server.lastbgsave_status == REDIS_OK))
            {
                redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...",
                    sp->changes, (int)sp->seconds);
                rdbSaveBackground(server.rdb_filename);
                break;
            }
         }

查看odb文件,如下,set 一个msgkey的内容为aaa,rdb文件如下:

redis 127.0.0.1:6379> keys *
(empty list or set)
redis 127.0.0.1:6379> set msg aaa

redis 127.0.0.1:6379> BGSAVE

Background saving started
[[email protected] bin]# od -c dump.rdb
0000000 R E D I S 0 0 0 6 376 \0 \0 003 m s g
0000020 003 a a a 377 241 362 266 \f Z ` 030 265
0000035

0000000 R E D I S 0 0 0 6 :代表RDB文件标志及版本

376 \0 :切换到数据库0

\0 :类型,代表字符串类型

003 m s g:003代表key长度,msg为键

003 a a a:003代表内容长度,aaa代表值

377:代表EOF

后面的241.。。。。265:代表校验和

可以再继续看一个切换到db 1的list集合

redis 127.0.0.1:6379> select 1
OK
redis 127.0.0.1:6379[1]> rpush listkey "aa" "ccc"
(integer) 2
redis 127.0.0.1:6379[1]> BGSAVE
Background saving started
redis 127.0.0.1:6379[1]>
You have mail in /var/spool/mail/root
[[email protected] bin]# od -c dump.rdb
0000000 R E D I S 0 0 0 6 376 001 \n \a l i s
0000020 t k e y 024 024 \0 \0 \0 016 \0 \0 \0 002 \0 \0
0000040 002 a a 004 003 c c c 377 377 } y 232 302 X h
0000060 g &
0000062

 





















以上是关于Redis 设计与实现(第九章) -- 持久化RBD的主要内容,如果未能解决你的问题,请参考以下文章

第九章 集合

[第九章]设计模式

第九章 数据管理

VLSI数字信号处理系统——第九章滤波器和变换中的算法强度缩减

Redis过期策略

架构:第九章:架构设计(为什么要这么设计,解决了什么问题)