数据库
首页 > 数据库> > 【Redis 干货领域】从底层彻底吃透 AOF 重写 (原理篇)

【Redis 干货领域】从底层彻底吃透 AOF 重写 (原理篇)

作者:互联网

每日一句
不要轻易去依赖一个人,它会成为你的习惯,当分别来临,你失去的不是某个人,而是你精神的支柱。无论何时何地,都要学会独立行走,它会让你走得更坦然些。

前提介绍
为了保证缓存数据的完整性和可靠性,Redis 提供两种持久化机制:

本文只关心 AOF,Redis Server 将所有写入的命令转换成 RESP 协议文本的方式写入 AOF 文件。

AOF 的实现
Redis 的 AOF 是类似于 log 的机制,每次写操作都会写到硬盘上,当系统崩溃时,可以通过 AOF 来恢复数据。每个带有写操作的命令被 Redis 服务器端收到运行时,该命令都会被记录到 AOF 文件上。由于只是一个 append 到文件操作,所以写到硬盘上的操作往往非常快。

其实 Redis AOF 机制包括了两件事, Rewrite 和 AOF,因为 AOF 主要采用的方式属于 Append Of File 的方式追加是文档存储, 本质内容暂时不考虑,本章重点内容是 Rewrite 机制 。

AOF 执行案例
Redis Server 收到 set key value 的的写入命令,Redis server 会进行以下几步操作:

<code data-type="codeline">*3</code><code data-type="codeline">$3</code><code data-type="codeline">SET</code><code data-type="codeline">$3</code><code data-type="codeline">KEY</code><code data-type="codeline">$5</code><code data-type="codeline">VALUE</code>

复制代码

重写的介绍

重写的实现

重写的类型
本文只关心 BGREWRITE 的问题,因此只介绍此命令的实现机制。

重写的流程
1.Redis Server 启动,如果 AOF 机制打开那么初始化 AOF 状态,并且如果存在 AOF 文件,读取 AOF 文件。

2.随着 Redis 不断接受命令,每个写命令都被添加到 AOF 文件,AOF 文件膨胀到需要 rewrite 阈值时又或者接收到客户端的 bgrewriteaof 命令。

3.fork 出一个子进程进行 rewrite,而父进程继续接受命令,现在的写操作命令都会被额外添加到一个 aof_rewrite_buf_blocks 缓冲中。

4.当子进程 rewrite 结束后,父进程收到子进程退出信号,把 aof_rewrite_buf_blocks 的缓冲添加到 rewrite 后的文件中,然后切换 AOF 的文件 fd。(此部分过程需要阻塞)

5.rewrite 任务完成,继续第二个步骤。

实现关键点

异步重写的支持
Redis Server 收到 BGREWRITE 命令或者系统自动触发 AOF 重写时,主进程创建一个子进程并进行 AOF 重写,主进程异步等待子进程结束(信号量),此时主进程能正常接收处理用户请求,用户请求会修改数据库里数据,会使得当前数据库的数据跟重写后 AOF 里不一致,需要有种机制保证数据的一致性。当前的做法是在重写 AOF 期间系统会新开一块内存用于缓存重写期间收到的命令,在重写完成以后再将缓存中的数据追加到新的 AOF。

在处理命令时既要将命令追加到 aof_buf,也要追加到重写 AOF Buffer。

Rewrite 存在的问题
重写 AOF Buffer 是个不限大小的 buffer,但用户写入的数据量较多时会出现以下两个问题:

1.占用过多内存,浪费资源;

2.主进程将 AOF buffer 数据写入到新 AOF 文件中时会阻塞工作线程,用户正常请求的延时会变高,严重情况下会超时,主备同步也会出问题,断开重连,重新同步等。

自动触发条件
AOF 里存放了所有的 redis 操作指令,文件达到条件或者手动 bgrewriteaof 命令都可以触发 rewrite。

rewrite 之后 aof 文件会保存 keys 的最后的状态,清除掉之前冗余的,来缩小这个文件.

<code data-type="codeline">long long growth =(server.appendonly_current_size*100/base) - 100; </code><code data-type="codeline">if (growth >=server.auto_aofrewrite_perc)</code>

复制代码

在配置文件里设置过:

auto-aof-rewrite-percentage 100 (当前写入日志文件的大小超过上一次 rewrite 之后的文件大小的百分之 100 时就是 2 倍时触发 Rewrite)

此外那个 64m 的代码我就不列举了 我相信大家都知道 哈哈,以后的篇章我会从源码去分析介绍的,期待吧 哈哈。

后台 Rewrite 问题解决方案

官方解决方案(AOF_BUFFER_BLOCK 不进行阻塞)
主要思路是 AOF 重写期间,主进程跟子进程通过管道通信,主进程实时将新写入的数据发送给子进程,子进程从管道读出数据交缓存在 buffer 中,子进程等待存量数据全部写入 AOF 文件后,将缓存数据追加到 AOF 文件中 (不是主进程写入) ,此方案只是解决阻塞工作线程问题,但占用内存过多问题并没有解决。

新解决方案(buffer 配对文件机制)
主要思路是 AOF 重写期间,主进程创建一个新的 aof_buf,新的 AOF 文件用于接收新写入的命令,sync 策略保持不变,在 AOF 重写期间,系统需要向两个 aof_buf,两个 AOF 文件同时追加新写入的命令。当主进程收到子进程重写 AOF 文件完成后,停止向老的 aof_buf,AOF 文件追加命令,然后删除旧的 AOF 文件(流程跟原来保持一致);将将子进程新生成的 AOF 文件重命名为 appendonly.aof.last,具体流程如下:

1.停止向旧的 aof_buf,AOF 文件追加命令;

2.删除旧的的 appendonly.aof.last 文件;

3.交换两个 aof_buf,AOF 文件指针;

4.回收旧的 aof_buf,AOF 文件;

5.重命令子进程生成的 AOF 文件为 appendonly.aof.last;

系统运行期间同时存在两个 AOF 文件,一个是当前正在写的 AOF,另一个是存量的 AOF 数据文件。因此需要修改数据库恢复相关逻辑,加载 AOF 时先要加载存量数据 appendonly.aof.last,再加载 appendonly.aof。

码字不易 请大家给我点赞+关注+评论!一条龙

如果想要获取学习资料,可在下方获取联系方式;
或者想要一起讨论问题的也加入技术交流Q群

添加助手小姐姐的 VX:  Mlzg5201314zz 
或者加入技术交流Q群:614478470
记得备注[CSDN]

在这里插入图片描述

标签:AOF,aof,rewrite,Redis,原理篇,文件,进程,重写
来源: https://blog.csdn.net/m0_57227221/article/details/117047442