AOF重写过程详解

这里对AOF不做过多的介绍,着重于介绍AOF重写过程。可以看到下图,AOF会把客户端所有的写命令追加到【AOF缓冲区】,然后再写入系统内核缓冲区,AOF缓冲区根据对应的持久化方式(fsync策略)向硬盘做同步操作。这里会阻塞直到写入磁盘完成后返回,保证了数据持久化。

AOF持久化方式(fsync策略)有哪些?

  • appendfsync always:主线程调用 write 执行写操作后,后台线程立即会调用 fsync 函数同步 AOF 文件(刷盘),fsync 完成后线程返回,这样会严重降低 Redis 的性能。
  • appendfsync everysec:主线程调用 write 执行写操作后立即返回,由后台线程每秒钟调用 fsync 函数(系统调用)同步一次 AOF 文件。
  • appendfsync no:主线程调用 write 执行写操作后立即返回,让操作系统决定何时进行同步,Linux 下一般为 30 秒一次。

这3种持久化方式的主要区别在于fsync同步AOF文件的时机(刷盘)。

 为了说明重写过程,我们简化一下上述的这个图,忽略底层的一些逻辑:

 

基本上很多对AOF重写过程的描述都是文字描述,我们知道AOF重写是fork一个子进程进行的,文字描述如下:

AOF 文件重写期间,Redis 还会创建一个 【AOF 重写缓冲区】,该缓冲区会在子进程创建新 AOF 文件期间,记录服务器执行的所有写命令。当子进程完成创建新 AOF 文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾,使得新的 AOF 文件保存的数据库状态与现有的数据库状态一致。最后,服务器用新的 AOF 文件替换旧的 AOF 文件,以此来完成 AOF 文件重写操作。

在《Redis设计与实现》这本书中,对AOF重写过程的一段描述:

那么过程应该如下:

AOF重写是一个由歧义的名字,该功能时通过读取数据库中的键值对来实现的,程序无需对现有AOF文件进行任何读入、分析或者写入操作。即图中【AOF重写文件】是读取数据库中的键值对来实现的。 

我们可以看到,虽然说fork了子进程不会阻塞主进程(主线程,一样的,因为redis是单线程模式运行,说是进程/线程都是对的),但是在追加新命令、新AOF文件覆盖旧文件时,还是要阻塞进程的,但是比起直接阻塞进程进行重写的时间要短很多,可以忽略不计(这里很多地方都没有提到)。

其实,这里我一直有一个问题,就是为什么要多一个【AOF重写缓冲区】?答案虽然很容易找到,就是:

子进程在进行AOF重写期间,服务器进程还需要继续处理命令请求,而新的命令可能会对现有的数据库状态进行修改,从而使得服务器当前的数据库状态和重写后的AOF文件所保存的数据库状态不一致。Reids服务器设置了一个AOF重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令之后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区。这保证了新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致。

但是,一开始我的想法是,为什么不直接用【AOF缓冲区】?即我们创建子进程后,直接进行文件重写,然后最后再将【AOF缓冲区】中的新命令追加到新的AOF文件中,即

一开始我觉得是因为在fork子进程时,【AOF缓冲区】中还存在未写入AOF文件的数据。(这个地方发现很多都没有讲到,在创建子进程时,【AOF缓冲区】中未写入的数据怎么处理?) 但是现在我个人觉得应该是创建了子进程后不应该调用回主进程的任何东西了,或者说是为了保证主进程的AOF文件的处理工作如常工作(不会被其他地方调用,【AOF缓冲区】跟如果没有创建子进程的情况下起到的作用一模一样)。

然后回到上述提到的问题,创建子进程时,【AOF缓冲区】中存在未写入AOF文件的数据怎么处理?又是个人理解:

应该是在创建子进程时,主进程会阻塞(可以忽略不计,因为缓冲区中的数据很少,写入文件的时间很短)【AOF缓冲区】会先立即将数据写入AOF文件,以保证这部分数据不会丢失。

写到一半,突然觉得我上述的想法是错的。刚好记录下,其实这部分数据是不用管的。为什么呢?因为上面提到的AOF重写是基于数据库的。即虽然这部分缓冲区的数据未写入AOF文件,但是已经是存在在数据库中的了。所以其实这部分数据我们并不需要在意。我觉得同时也从另一方面解释了上一个问题,为什么我们需要多一个【AOF重写缓冲区】。因为我们在创建子进程的那一刻,我们是对数据库进行重写,而不是AOF文件,而【AOF缓冲区】中可能存在未写入AOF文件的数据,所以我们创建了一个新的缓冲区,是为了记录数据库的变化。

举个例子:

在时刻 t1 数据库中有“abcd”这个数据,【AOF缓冲区】中有“cd”数据还未写入AOF文件(注意区分AOF文件是缓存的持久化文件,并不是数据库的),这时我们创建了子进程进行AOF文件的重写。然后完成了AOF文件的重写是在 t2 时刻。从 t1 到 t2 这个时间段中,我们的主进程是正常的,即还是可以写入数据。在这个时间段中我们在数据库中增加了“ef”数据。那么在 t2 这个时刻会发生什么呢?即我们的旧AOF文件记录的有“ab”,【AOF缓冲区】的记录有“cdef”,假设【AOF缓冲区】的数据还未写入了旧AOF文件。而新AOF文件呢,由于我们是在 t1 时刻重写的,即它重写了 t1 时刻的数据库。所以它的记录有“abcd”。这时【AOF重写缓冲区】就发挥它的作用了,它是在重写期间数据库发生的数据变动的记录,即它记录了“ef”,再追加到新AOF文件中,我们就完成了数据的重写。(注意:此时的【AOF缓冲区】的记录是“cdef”,这也说明了为什么我们需要创建多一个缓冲区)

但这里应该就大概解释清楚了AOF重写的整体过程,如有建议或疑问欢迎交流~


参考

  • 《Redis 设计与实现》
  • Redis AOF 持久化详解 - 程序员历小冰:http://remcarpediem.net/article/376c55d8/

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Redis AOF重写是一种机制,用于解决AOF文件过大导致IO性能问题的情况。AOF重写过程并不需要对原有AOF文件进行读取、写入或分析操作,而是通过读取服务器当前的数据库状态来实现的。\[3\]AOF重写的执行流程包括命令追加、文件写入和文件同步以及文件重写。首先,Redis的写命令会被追加到缓冲区aof_buf中。然后,根据不同的同步策略,将aof_buf中的内容同步到硬盘,以确保数据的持久化。最后,定期进行AOF文件的重写,以达到压缩AOF文件的目的。\[3\]通过AOF重写,可以有效地减小AOF文件的大小,提高IO性能,同时保证数据的持久化。 #### 引用[.reference_title] - *1* *3* [缓存数据库REDIS之二:AOF重写原理](https://blog.csdn.net/qq_18343913/article/details/119343547)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [redisaof重写机制](https://blog.csdn.net/qq_63431773/article/details/131691454)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值