• Redis持久化的两种方式 RDB和AOF
  • 发布于 2个月前
  • 163 热度
    0 评论
  • 林丹丹
  • 0 粉丝 14 篇博客
  •   

Redis本身提供持久化功能,有两种持久化机制,一种是数据持久化RDB,一种是命令持久化AOF,这两种持久化方式各有优缺点,也可以组合使用。一旦组合使用,Redis在载入数据的时候会优先载入aof文件,只有当AOF持久化关闭的时候才会载入rdb文件。

1、RDB(Redis DataBase)

RDB是Redis数据库,Redis会根据一个配置来触发持久化:

#save <seconds> <changes>

save 900 1
save 300 10
save 60 10000

CONFIG GET save
1) "save"
2) "3600 1 300 100 60 10000"

表示在多少秒之类的变化次数,一旦达到这个触发条件Redis将触发持久化动作。

Redis在执行持久化的时候有两种模式BGSAVE、SAVE:

BGSAVE是后台保存,Redis会fork出一个子进程来处理持久化,不会block用户的执行请求;
SAVE则会block用户执行请求。

struct redisServer {
long long dirty;/* Changes to DB from the last save */
time_t lastsave; /* Unix time of last successful save */
long long dirty_before_bgsave;
pid_t rdb_child_pid;/* PID of RDB saving child */
struct saveparam *saveparams; /* Save points array for RDB */
}

struct saveparam {
    time_t seconds;
    int changes;
};

RedisServer包含的信息很多,其中就包含了有关于RDB持久化的信息。

redisServer->dirty至上次save到目前为止的change数。redisServer->lastsave上次save时间。

saveparam struct保存了我们通过save命令设置的参数,time_t是个long时间戳。

typedef __darwin_time_t     time_t;

typedef long    __darwin_time_t;    /* time() */

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
         for (j = 0; j < server.saveparamslen; j++) {
            struct saveparam *sp = server.saveparams+j;
            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;
            }
         }
}

Redis事件循环会周期性的执行serverCron方法,这段代码会循环遍历server.saveparams参数链表。

如果server.dirty大于等于我们参数里配置的变化并且server.unixtime-server.lastsave大于参数里配置的时间,并且server.unixtime-server.lastbgsave_try减去bgsave重试延迟时间,或者当前server.lastbgsave_status== REDIS_OK则执行rdbSaveBackground方法。


2、AOF(Append-only file)

AOF持久化是采用对文件进行追加对方式进行,每次追加都是Redis处理的命令。有点类似command sourcing命令溯源的模式,只要我们可以将所有的命令按照执行顺序在重放一遍就可以还原最终的Redis内存状态。


AOF持久化最大的优势是可以缩短数据丢失的间隔,做到秒级的丢失率。RDB会丢失上一个保存周期到目前的所有数据,只要没有触发save命令设置的save seconds changes阈值数据就会一直不被持久化。

struct redisServer {
 /* AOF buffer, written before entering the event loop */
 sds aof_buf;
 }

struct sdshdr {
    unsigned int len;
    unsigned int free;
    char buf[];
};

aof_buf是命令缓存区,采用sds结构缓存,每次当有命令被执行当时候都会写一次到aof_buf中。有几个配置用来控制AOF持久化的机制。

appendonly no 
appendfilename "appendonly.aof"

appendonly用来控制是否开启AOF持久化,appendfilename用来设置aof文件名。

appendfsync always
appendfsync everysec
appendfsync no

appendfsync用来控制命令刷盘机制。现在操作系统都有文件cache/buffer的概念,所有的写入和读取都会走cache/buffer,并不会每次都同步刷盘,因为这样性能一定会受影响。所以Redis也提供了这个选项让我们来自己根据业务场景控制。

always:每次将aof_buf命令写入aof文件并且执行实时刷盘。
everysec:每次将aof_buf命令写入aof文件,但是每隔一秒执行一次刷盘。
no:每次将aof_buf命令写入aof文件不执行刷盘,由操作系统来自行控制。

AOF也是采用后台子进程的方式进行,与主进程共享数据空间也就是aof_buf,但是只要开始了AOF子进程之后Redis事件循环文件事件处理器会将之后的命令写入另外一个aof_buf,这样就可以做到平滑的切换。


AOF会不断的追加命令进aof文件,随着时间和并发量的加大aof文件会极速膨胀,所以有必要对这个文件大小进行优化。Redis基于rewrite重写对文件进行压缩。

no-appendfsync-on-rewrite no/yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

no-appendfsync-on-rewrite控制是否在bgrewriteaof的时候还需要进行命令追加,如果追加可能会出现磁盘IO跑高现象。

上面说过,当AOF进程在执行的时候原来的事件循环还会正常的追加命令进aof文件,同时还会追加命令进另外一个aof_buf,用来做新aof文件的重写。这是两条并行的动作,如果我们设置成yes就不追加原来的aof_buf 因为新的aof文件已经包含了之后进来的命令。


auto-aof-rewrite-percentage和auto-aof-rewrite-min -size64mb这两个配置前者是文件增长百分比来进行rewrite,后者是按照文件大小增长进行rewrite。

用户评论