Redis之AOF重写及其实现原理

本文详细介绍了Redis中AOF重写机制的实现原理及其后台重写的过程,包括如何避免数据不一致的问题,以及触发AOF后台重写的条件。

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

参考网址:http://blog.youkuaiyun.com/hezhiqiang1314/article/details/69396887


AOF 重写

  • AOF 持久化是通过保存被执行的写命令来记录数据库状态的,所以AOF文件的大小随着时间的流逝一定会越来越大;影响包括但不限于:计算机的存储压力;AOF还原出数据库状态的时间增加;
  • 为了解决AOF文件体积膨胀的问题,Redis提供了AOF重写功能:Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个文件所保存的数据库状态是相同的,但是新的AOF文件不会包含任何浪费空间的冗余命令,通常体积会较旧AOF文件小很多。

AOF 文件重写的实现

  • AOF重写并不需要对原有AOF文件进行任何的读取,写入,分析等操作,这个功能是通过读取服务器当前的数据库状态来实现的。
         * 当前列表键list在数据库中的值就为["C", "D", "E", "F", "G"]。要使用尽量少的命令来记录list键的状态,最简单的方式不是去读取和分析现有AOF文件的内容,,而是直接读取list键在数据库中的当前值,然后用一条RPUSH list "C" "D" "E" "F" "G"代替前面的6条命令。



AOF重写功能的实现原理

  • 首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录该键值对的多个命令;
         *实际为了避免执行命令时造成客户端输入缓冲区溢出,重写程序在处理list hash set zset时,会检查键所包含的元素的个数,如果元素的数量超过了redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD常量的值,那么重写程序会使用多条命令来记录键的值,而不是单使用一条命令。该常量默认值是64– 即每条命令设置的元素的个数 是最多64个,使用多条命令重写实现集合键中元素数量超过64个的键


AOF后台重写

  • aof_rewrite函数可以创建新的AOF文件,但是这个函数会进行大量的写入操作,所以调用这个函数的线程将被长时间的阻塞,因为Redis服务器使用单线程来处理命令请求;所以如果直接是服务器进程调用AOF_REWRITE函数的话,那么重写AOF期间,服务器将无法处理客户端发送来的命令请求;
  • Redis不希望AOF重写会造成服务器无法处理请求,所以Redis决定将AOF重写程序放到子进程(后台)里执行。这样处理的最大好处是:
    • 子进程进行AOF重写期间,主进程可以继续处理命令请求;
    • 子进程带有主进程的数据副本保证数据的安全性

使用子进程进行AOF重写的问题

  • 子进程在进行AOF重写期间,服务器进程还要继续处理命令请求,而新的命令可能对现有的数据进行修改,这会让当前数据库的数据和重写后的AOF文件中的数据不一致。

如何修正

  • 为了解决这种数据不一致的问题,Redis增加了一个AOF重写缓存,这个缓存在fork出子进程之后开始启用,Redis服务器主进程在执行完写命令之后,会同时将这个写命令追加到AOF缓冲区和AOF重写缓冲区
  • 即子进程在执行AOF重写时,主进程需要执行以下三个工作:
    • 执行client发来的命令请求;
    • 将写命令追加到现有的AOF文件中;
    • 将写命令追加到AOF重写缓存中。


效果

  • 可以保证:
    • AOF缓冲区的内容会定期被写入和同步到AOF文件中,对现有的AOF文件的处理工作会正常进行
    • 从创建子进程开始,服务器执行的所有写操作都会被记录到AOF重写缓冲区中;

完成AOF重写之后

  • 当子进程完成对AOF文件重写之后,它会向父进程发送一个完成信号,父进程接到该完成信号之后,会调用一个信号处理函数,该函数完成以下工作:

    • 将AOF重写缓存中的内容全部写入到新的AOF文件中;这个时候新的AOF文件所保存的数据库状态和服务器当前的数据库状态一致;
    • 对新的AOF文件进行改名,原子的覆盖原有的AOF文件;完成新旧两个AOF文件的替换。
  • 当这个信号处理函数执行完毕之后,主进程就可以继续像往常一样接收命令请求了。在整个AOF后台重写过程中,只有最后的“主进程写入命令到AOF缓存”和“对新的AOF文件进行改名,覆盖原有的AOF文件。”这两个步骤(信号处理函数执行期间)会造成主进程阻塞,在其他时候,AOF后台重写都不会对主进程造成阻塞,这将AOF重写对性能造成的影响降到最低。

以上,即AOF后台重写,也就是BGREWRITEAOF命令的工作原理。

触发AOF后台重写的条件

  • AOF重写可以由用户通过调用BGREWRITEAOF手动触发。
  • 服务器在AOF功能开启的情况下,会维持以下三个变量:

    • 记录当前AOF文件大小的变量aof_current_size
    • 记录最后一次AOF重写之后,AOF文件大小的变量aof_rewrite_base_size
    • 增长百分比变量aof_rewrite_perc
  • 每次当serverCron(服务器周期性操作函数)函数执行时,它会检查以下条件是否全部满足,如果全部满足的话,就触发自动的AOF重写操作:

    • 没有BGSAVE命令(RDB持久化)/AOF持久化在执行;
    • 没有BGREWRITEAOF在进行;
    • 当前AOF文件大小要大于server.aof_rewrite_min_size(默认为1MB),或者在redis.conf配置了auto-aof-rewrite-min-size大小;
    • 当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比(在配置文件设置了auto-aof-rewrite-percentage参数,不设置默认为100%)

如果前面三个条件都满足,并且当前AOF文件大小比最后一次AOF重写时的大小要大于指定的百分比,那么触发自动AOF重写。


总结

  • AOF重写的目的是为了解决AOF文件体积膨胀的问题,使用更小的体积来保存数据库状态,整个重写过程基本上不影响Redis主进程处理命令请求;
  • AOF重写其实是一个有歧义的名字,实际上重写工作是针对数据库的当前状态来进行的,重写过程中不会读写原来的AOF文件;
  • AOF可以由用户手动触发,也可以由服务器自动触发。



### Redis AOF 重写的详细过程和原理 RedisAOF(Append Only File)持久化机制通过记录服务器执行的写命令来确保数据的安全性。然而,随着运行时间的增长,AOF 文件可能会变得非常庞大,导致加载时间过长,影响性能。为了解决这一问题,Redis 引入了 AOF 重写机制。 #### AOF 重写的触发条件 AOF 重写可以通过以下几种方式触发[^4]: - 手动执行 `BGREWRITEAOF` 命令。 - 主从复制完成后,无论 RDB 文件解析和加载是否成功。 - AOF 重写被设置为待调度执行。 - AOF 被启用,同时 AOF 文件的大小比例超出配置的阈值(如 `auto-aof-rewrite-min-size` 和 `auto-aof-rewrite-percentage`),并且 AOF 文件的绝对大小也超出设定的最小值。 #### AOF 重写实现原理 AOF 重写的核心思想是生成一个新的、更紧凑的 AOF 文件,其中包含最少的写命令集合,能够重建当前的数据库状态。以下是其具体实现过程: 1. **Fork 子进程**:Redis 主进程通过 `fork` 系统调用创建一个子进程。子进程会继承父进程的内存页表,但由于写时复制(Copy-On-Write, COW)机制,父子进程在初始状态下共享同一份物理内存,只有当某个进程修改内存时才会分配新的页面[^1]。 2. **扫描内存数据**:子进程遍历 Redis 当前内存中的所有键值对,并将这些数据转换为一组高效的写命令。例如,如果某个列表包含多个元素,子进程不会逐条记录每个 `LPUSH` 或 `RPUSH` 操作,而是直接生成一个 `DEL` 和 `RPUSH` 的组合命令来表示整个列表的状态[^3]。 3. **生成新文件**:子进程将这些优化后的写命令写入到一个临时文件中(通常命名为 `temp-rewriteaof.aof`)。此过程完全由子进程完成,主进程可以继续处理客户端请求,从而避免阻塞。 4. **替换旧文件**:当子进程完成新 AOF 文件的生成后,它会通知父进程。父进程将旧的 AOF 文件原子性地替换为新的 AOF 文件,确保操作过程中不会丢失任何数据。 5. **同步写操作**:在子进程执行重写期间,主进程仍然会接收新的写命令。为了保证数据一致性,主进程会将这些命令同时追加到旧的 AOF 文件和一个缓冲区中。当重写完成后,缓冲区中的命令会被追加到新的 AOF 文件末尾,确保所有数据都被正确持久化[^3]。 #### AOF 重写的优点 - 减少 AOF 文件的体积,缩短加载时间,提高 Redis 的启动效率。 - 通过合并冗余命令,降低写入操作的复杂度,提升性能。 - 利用 COW 机制,最大限度地减少对主进程的影响,保持 Redis 的高可用性。 #### 示例代码 以下是一个简单的示例,展示如何手动触发 AOF 重写: ```bash # 使用 BGREWRITEAOF 命令触发 AOF 重写 redis-cli BGREWRITEAOF ``` #### 注意事项 - 配置参数 `auto-aof-rewrite-min-size` 和 `auto-aof-rewrite-percentage` 决定了自动触发 AOF 重写的条件。合理调整这些参数可以平衡性能和存储需求[^4]。 - 在高并发场景下,频繁的 AOF 重写可能会增加磁盘 I/O 压力,因此需要根据实际业务需求进行优化。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值