高频面试题——Redis 的 AOF 持久化

有理想的菜鸡

共 2445字,需浏览 5分钟

 · 2021-05-10

良心公众号

关注不迷路



01

AOF 持久化背景


在之前的高频面试题——Redis 的 RDB 持久化文章中,我们讨论了 Redis 的 RDB 持久化。由于 RDB 文件的写入并不是实时的,通过 RDB 文件仅仅能将数据库状态恢复到上一次 RDB 持久化的状态,在此之后所做的改动将会被丢失,因此,RDB 持久化比较适用于对数据丢失不敏感的场合。


为了应对对数据丢失比较敏感的场合,Redis 提供了另外一种持久化的方式,也就是本文要提到的 AOF 持久化



02

AOF 持久化简介


与 RDB 持久化通过保存数据库中的键值对来记录数据库状态的方式不同,AOF 持久化是通过保存 Redis 服务所执行的写命令来记录数据库状态的。



03

AOF 持久化原理


AOF 持久化功能的具体实现可以分为:命令追加文件写入与同步


命令追加

当开启 AOF 持久化功能之后,Redis 服务器在执行完成一个写命令之后,会将该命令追加到 aof_buf 缓冲区末尾。


文件写入与同步

当命令追加到 aof_buf 缓冲区末尾,Redis 进程会调用 flushAppendOnlyFile 方法,然后根据配置来决定是否将 aof_buf 缓冲区中的内容写入和保存到 AOF 文件中。这个配置是由 redis.conf 中的 appendfsync 选项的值来决定的。


appendfsync 的值有如下三个选项:

  • always: 将 aof_buf 缓冲区中的所有内容写入并同步到 AOF 文件。

  • everysec (默认): 将 aof_buf 缓冲区中的所有内容写入到 AOF 文件,但是否同步 AOF 文件取决于和上次同步的时间间隔是否超过一秒钟。

  • no: 将 aof_buf 缓冲区中的所有内容写入到 AOF 文件,但不主动对其进行同步,具体何时同步 AOF 文件由操作系统决定。


appendfsync 这三种选项实际上就是对于 AOF 写入和同步的三种策略。

  • always 策略是最为严格的,每次 flushAppendOnlyFile 都需要对 AOF 文件进行同步,因此效率最低,但换来的是较高的数据安全性,如果系统宕机,仅仅会丢失当前事件循环中执行的写入命令。

  • everysec 策略的严格程度次之,对于 AOF 文件的同步是以一秒钟为间隔的,因此效率相对高一些,但也就会有数据安全性方面的损失,如果系统宕机,会丢失最近一秒钟执行的写入命令。

  • no 策略的严格程度最弱,在 执行 flushAppendOnlyFile 方法期间,不会对 AOF 文件进行同步,因此效率最高,但数据安全性方面最弱,同时,在操作系统对于 AOF 文件进行同步的时候,由于期间可能积攒了大量的命令,所以单次同步时间会比较长,同时,如果系统宕机,会丢失从上次同步之后的所有写入命令。


由于 AOF 文件中包含了重建数据库状态所需的所有写入命令 (不考虑数据丢失情况),因此,服务器只需要读取 AOF 文件并执行其中的命令,即可还原服务器之前的状态,这也就实现了 AOF 持久化。



04

AOF 文件重写


细心的小伙伴可能会发现一个问题,随着时间的流逝,写入命令的量可能是巨大的,这会导致 AOF 文件的不断膨胀,这不仅会占用更多计算资源,也会在使用 AOF 文件还原数据的时候耗费更多的时间。为了解决这个问题,Redis 提供了 AOF 文件重写功能。


值得注意的是,AOF 文件重写的分析对象并不是现有的 AOF 文件,而是当前的数据库状态。举个例子:

redis> RPUSH numbers 1redis> RPUSH numbers 2redis> RPUSH numbers 3redis> LPOP numbers


在对 numbers 键执行上述命令时,服务器为了保存当前 numbers 键的状态,会在 AOF 文件中写入上述四条命令。但在进行 AOF 重写时,对 numbers 键的状态进行分析,只需要保存下面这一条命令即可:

redis> RPUSH numbers 2 3


这就是 AOF 文件重写的基本原理,通过 AOF 文件重写,可以将针对于同一个键的众多命令进行合并,大大减少命令数量,从而达到节省资源和提高效率的目的。


值得注意的是,由于 AOF 文件重写方法可能会执行大量的写入操作,因此,执行该方法的线程会被阻塞,由于 Redis 服务器是单线程的,因此,由 Redis 服务器线程来执行 AOF 文件重写方法是不合适的。对此,Redis 的处理是将 AOF 文件重写方法放到子进程里进行执行,这样可以避免阻塞服务器进程。同时,子进程持有服务器进程的数据副本,从而避免了数据共享,在不必考虑加锁的情况下保证了数据安全。


05

数据一致性


那么问题又来了,子进程在执行 AOF 文件重写期间,服务器很有可能会接收到新的写命令,此时,如何保证子进程和服务器进程数据一致呢?Redis 为了解决这个问题,引入了 AOF 重写缓冲区的概念。当 Redis 服务器执行写命令之后,会同时将这个写命令发送到 AOF 缓冲区和 AOF 重写缓冲区。当子进程完成 AOF 重写之后,会向父进程发送一个信号,父进程接收到信号之后,会将 AOF 重写缓冲区中的内容写入到新的 AOF 文件中,并用新的 AOF 文件原子地覆盖掉旧的 AOF 文件。


综上所述,本文关于 Redis 的 AOF 持久化机制就总结到这里了。


欢迎关注【有理想的菜鸡】公众号,大家一起讨论技术,共同成长!



06

相关阅读


Redis 的五种基本类型(实战篇)

Redis 的五种基本类型(原理篇)

高频面试题——Redis 的 RDB 持久化



07

参考资料


《Redis 设计与实现》黄健宏 著

https://github.com/redis/redis

4f48d15f6618fc33e867965031af46b7.webp

学习 | 工作 | 分享

👆关注“有理想的菜鸡

只有你想不到,没有你学不到
浏览 19
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报