redis2.4版的自动bgrewriteaof

2.4版本做了很多功能改进,尤其是aof这块变动较大.增加了自动的bgrewriteaof;开启两个后台线程来避免主线程fsync,rename,close等阻塞操作,另外修复了出现重复命令进入aof文件的bug,下面是基于2.4.1.的源码aof这块的改进分析.

自动的bgrewriteaof

为了避免aof文件过大,我们会周期性的做bgrewriteaof来重整aof文件.以前我们会额外的配置crontab在业务低峰期执行这个命令,这额外的增加一个workaroud的脚本任务在大集群里是很糟糕的,不易检查,出错无法即时发现.

于是这个自动bgrewriteaof功能被直接加到redis的内部.首先对于aof文件,server对象添加一个字段来记录aof文件的大小server.appendonly_current_size,每次aof发生变化都会维护这个字段.

aof.c
=================
116     nwritten = write(server.appendfd,server.aofbuf,sdslen(server.aofbuf));
.....
128     server.appendonly_current_size += nwritten;

bgrewriteaof完毕或者实例启动载入aof数据后也会调用aofUpdateCurrentSize这个函数维护这个字段,同时会记录下此时的aof文件的大小server.auto_aofrewrite_base_size作为基准值,用于接下来判断aof增长率.

aof.c
=================
385     aofUpdateCurrentSize();
386     server.auto_aofrewrite_base_size = server.appendonly_current_size;

有了当前值和基准值我们就可以判断aof文件的增长情况.另外还需要配置两个参数来判断是否需要自动触发bgrewriteaof.

redis.h
===============
int auto_aofrewrite_perc;       /* Rewrite AOF if % growth is > M and... */
off_t auto_aofrewrite_min_size; /* the AOF file is at least N bytes. */

auto_aofrewrite_perc: aof文件的大小超过基准百分之多少后触发bgrewriteaof.默认这个值设置为100,意味着当前aof是基准大小的两倍的时候触发bgrewriteaof.把它设置为0可以禁用自动触发的功能.
auto_aofrewrite_min_size: 当前aof文件大于多少字节后才触发.避免在aof较小的时候无谓行为.默认大小为64mb.
两个参数都是可以在conf里静态配置,或者通过config set来动态修改的.

redis 127.0.0.1:6379> config get auto-aof-rewrite-percentage
1) "auto-aof-rewrite-percentage"
2) "100"
redis 127.0.0.1:6379> config get auto-aof-rewrite-min-size
1) "auto-aof-rewrite-min-size"
2) "1048576"
redis 127.0.0.1:6379> config get auto-aof-rewrite-min-size
1) "auto-aof-rewrite-min-size"
2) "1048576"
redis 127.0.0.1:6379> config set auto-aof-rewrite-percentage 200
OK
redis 127.0.0.1:6379> config set auto-aof-rewrite-min-size 10485760
OK

然后就是触发检查的主逻辑,serverCron时间事件中每次都会检查现有状态和参数来判断是否需要启动bgrewriteaof.

redis.c
===============
635          if (server.bgsavechildpid == -1 &&
 636              server.bgrewritechildpid == -1 &&
 637              server.auto_aofrewrite_perc &&
 638              server.appendonly_current_size > server.auto_aofrewrite_min_size)
 639          {
 640             long long base = server.auto_aofrewrite_base_size ?
 641                             server.auto_aofrewrite_base_size : 1;
 642             long long growth = (server.appendonly_current_size*100/base) - 100;
 643             if (growth >= server.auto_aofrewrite_perc) {
 644                 redisLog(REDIS_NOTICE,"Starting automatic rewriting of AOF on %lld%% growth",growth);
 645                 rewriteAppendOnlyFileBackground();
 646             }
 647         }

以上代码显示,如果aof文件增长百分率growth大于auto_aofrewrite_perc,则自动的触发后一个bgrewriteaof.

延迟bgrewriteaof

这是个小的改进,手动触发的bgrewriteaof的时候如果同时存在bgsave在备份,会推迟这次操走的事件,设置server.aofrewrite_scheduled=1,待到bgsave结束后的下一次serverCron里才会触发.

设置aofrewrite_scheduled=1

aof.c
706 void bgrewriteaofCommand(redisClient *c) {
707     if (server.bgrewritechildpid != -1) {
708         addReplyError(c,"Background append only file rewriting already in progress");
709     } else if (server.bgsavechildpid != -1) {
710         server.aofrewrite_scheduled = 1;
711         addReplyStatus(c,"Background append only file rewriting scheduled");
712     } else if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
713         addReplyStatus(c,"Background append only file rewriting started");
714     } else {
715         addReply(c,shared.err);
716     }
717 }

触发bgrewriteaof

redis.c
 598     if (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1 &&
 599         server.aofrewrite_scheduled)
 600     {
 601         rewriteAppendOnlyFileBackground();
 602    }

在2.4.1的这里存在一个bug,因为没有地方把server.aofrewrite_scheduled = 0;在刚发布的2.4.2里fix了这个bug.

One Comment

  1. [...] 引入了延迟bgrewriteaof来避免与bgsave同时写文件,而server.no_appendfsync_on_rewrite参数的设置又避免了bgrewriteaof时主线程出现fsync. [...]

Leave a Reply