zoukankan      html  css  js  c++  java
  • 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
    [root@test bin]# od -c dump.rdb
    0000000 R E D I S 0 0 0 6 376 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

    :类型,代表字符串类型

    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
    [root@test bin]# od -c dump.rdb
    0000000 R E D I S 0 0 0 6 376 001 a l i s
    0000020 t k e y 024 024 016 002
    0000040 002 a a 004 003 c c c 377 377 } y 232 302 X h
    0000060 g &
    0000062

  • 相关阅读:
    迟到的恶劣影响
    spring boot 向数据库写入海量数据
    分析 SQL 执行过程
    Mysql 索引 BTree 与 Hash
    Mysql 数据库设计
    Jdk 源码下载方式
    深入理解JVM虚拟机-周志明【第三版】
    Elasticsearch 查询实践
    MFC程序运行流程

  • 原文地址:https://www.cnblogs.com/dpains/p/7622375.html
Copyright © 2011-2022 走看看