REDIS AOF的实现

本文详细探讨了REDIS AOF的工作流程,包括Appendfsync和no-appendfsync-on-rewrite配置的影响。在每次更新操作后,命令会被写入aofbuf,并在事件循环结束时进行fsync操作。根据配置,fsync可能由主线程或专门的fsync线程执行。此外,还介绍了AOF的rewrite过程,由后台子进程完成,通过复制当前数据库状态到临时文件,然后由父进程将后续更新追加到新文件,最后完成文件替换。这一过程展示了如何确保主线程性能并保障数据持久化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Redis AOF
上文我们介绍了Redis的主框架,以及两种持久化大概原理。本文我们将从源码角度分析Redis AOF的相关实现。(本文基于的版本为2.4.2)
1. 相关配置项
首先我们看一下redis.conf里的关于AOF的配置选项:
Appendonly(yes,no):是否开启AOF持久化
Appendfilename(log/appendonly.aof):AOF日志文件
Appendfsync(always,everysec,no):AOF日志文件同步的频率,always代表每次写都进行fsync,everysec每秒钟一次,no不主动fsync,由OS自己来完成。
no-appendfsync-on-rewrite(yes,no):进行rewrite时,是否需要fsync
auto-aof-rewrite-percentage(100):当AOF文件增长了这个比例(这里是增加了一倍),则后台rewrite自动运行
auto-aof-rewrite-min-size(64mb):进行后面rewrite要求的最小AOF文件大小。这两个选项共同决定了后面rewrite进程是否到达运行的时机
注:rewrite是指当AOF很大的时候,通过重写内存的数据来删除原来的AOF文件,生成最新的内存数据的AOF日志,即把当前的结果逆转化为相应的操作命令写到AOF文件中。
通过上面的选项我们可以知道redis的三个AOF处理流程:
 每次更新操作进行的AOF写操作(涉及同步频率)
 Rewrite,当满足auto-aof-rewrite-percentage,auto-aof-rewrite-min-size时后面自动运行rewrite操作。
 Rewrite,当收到bgrewriteaof客户端命令时,马上运行后面rewrite操作
注:当某个key过期的时候也会写AOF,其实它跟第一种很类似,这里就不再介绍。下面我们将分别介绍这三个流程。
在redis的较新版本中(不知道从哪个版本开始)增加了两个新的子进程:
 REDIS_BIO_CLOSE_FILE,负责所有的close file操作
 REDIS_BIO_AOF_FSYNC,负责fsync操作
因为这两个操作都可能会引起阻塞,如果在主线程中完成的话,会影响系统对事件的响应,所以这里统一由相应的线程来完成,每个线程都有一个自己的bio_jobs list,用来保存需要的处理的job任务。其相应的代码在bio.c(线程处理函数为bioProcessBackgroundJobs)里,这两个线程在initServer时创建bioInit()。
注:标准命令格式:如set aaa xiang
*3\r\n$3\r\nset\r\n$3\r\n\aaa\r\n$5\r\n\xiang\r\n
其中*3表示该命令的参数个数,后面的数字表示每个参数的长度。

2. AOF的处理流程
2.1 每次更新操作的AOF写

主要涉及的配置是:Appendfsync,no-appendfsync-on-rewrite。该操作的入口在(redis.c):

void call(redisClient *c) {
    dirty = server.dirty;  //上次的脏数据个数
    c->cmd->proc(c);    //执行命令操作,如果该操作是一个更新操作,则server.dirty会增加
    dirty = server.dirty-dirty; //此次执行导致的脏数据个数
    …
    if (server.appendonly && dirty > 0) //有脏数据并且开启了AOF功能
        feedAppendOnlyFile(c->cmd,c->db->id,c->argv,c->argc); //将数据保存到server.aofbuf
…
}

我们再来看一下feedAppendOnlyFile的实现

void feedAppendOnlyFile(struct redisCommand…{
if (dictid != server.appendseldb){ //当月操作的db与上一次不一样,所以要重新写一个新的select db命令,当rewrite的时候也会把appendseldb置为-1
        buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
            (unsigned long)strlen(seldb),seldb);
        server.appendseldb = dictid;
}
…
buf = catAppendOnlyGenericCommand(buf,argc,argv); //转换为标准命令格式
server.aofbuf = sdscatlen(server.aofbuf,buf,sdslen(buf)); //将命令写到aofbuf,这个buf会在serverCron当Appendfsync到满足时fsync到文件
if (server.bgrewritechildpid != -1) //如果有bgrewrite子进程的话,则也必须把该命令保存到bgrewr
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值