Redis WAL

AOF日志是如何实现的

WAL,指数据库的写前日志(Write Ahead Log, WAL):在实际写数据前,先把修改的数据记到日志文件中,以便故障时进行恢复。

不过,AOF 日志(Append Only File)正好相反,它是写后日志,“写后”的意思是 Redis 是先执行命令,把数据写入内存,然后才记录日志,如下图所示:

AOF 先执行命令再记日志的优缺点

传统数据库的日志,例如 redo log(重做日志),记录的是修改后的数据。
而AOF 里记录的是 Redis 收到的每一条命令,这些命令是以文本形式保存的。

优点
写后日志这种方式,就是先让系统执行命令,只有命令能执行成功,才会被记录到日志中,否则,系统就会直接向客户端报错。可以避免出现记录错误命令的情况。
它是在命令执行后才记录日志,所以不会阻塞当前的写操作。
存在两个风险

首先,如果刚执行完一个命令,还没有来得及记日志就宕机了,那么这个命令和相应的数据就有丢失的风险。
其次,AOF 虽然避免了对当前命令的阻塞,但可能会给下一个操作带来阻塞风险。

AOF 机制给我们提供了三个选择,也就是 AOF 配置项 appendfsync 的三个可选值。

Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

随着接收的写命令越来越多,AOF 文件会越来越大。这也就意味着,我们一定要小心 AOF 文件过大带来的性能问题。
需要AOF 重写机制

AOF重写机制

  • 为了解决 AOF 文件过大的问题,Redis 引入了 AOF 重写机制,它可以压缩和优化 AOF 文件的内容,减少冗余和无效的命令,提高数据的存储效率和恢复速度 。
  • AOF 重写机制的原理是根据 Redis 进程内的数据生成一个新的 AOF 文件,只包含当前有效和存在的数据的写入命令,而不是历史上所有的写入命令 。
  • AOF 重写机制是通过 fork 出一个子进程来完成的,子进程会扫描 Redis 的数据库,并将每个键值对转换为相应的写入命令,然后写入到一个临时文件中 。
  • 在子进程进行 AOF 重写的过程中,主进程还会继续接收和处理客户端的请求,如果有新的写操作发生,主进程会将这些写操作追加到一个缓冲区中,并通过管道通知子进程 。
  • 子进程在完成 AOF 重写后,会将缓冲区中的写操作也追加到临时文件中,然后向主进程发送信号,通知主进程可以切换到新的 AOF 文件了 。
  • 主进程在收到子进程的信号后,会将缓冲区中的写操作再次追加到临时文件中(以防止在此期间有新的写操作发生),然后用临时文件替换旧的 AOF 文件,并关闭旧的 AOF 文件 。

出发方式

  • AOF 重写机制可以由用户手动触发,也可以由系统自动触发 。
  • 用户手动触发 AOF 重写机制可以通过执行 BGREWRITEAOF 命令来实现 。
  • 系统自动触发 AOF 重写机制可以通过配置文件中的 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 参数来控制 。
  • auto-aof-rewrite-percentage 参数表示当当前 AOF 文件大小超过上次重写后 AOF 文件大小的百分比时,触发 AOF 重写机制,默认值为 100 。
  • auto-aof-rewrite-min-size 参数表示当当前 AOF 文件大小超过指定值时,才可能触发 AOF 重写机制,默认值为 64 MB 。
  • 系统自动触发 AOF 重写机制还需要满足以下条件 :

    • 当前没有正在执行 BGSAVE 或 BGREWRITEAOF 的子进程
    • 当前没有正在执行 SAVE 的主进程
    • 当前没有正在进行集群切换或故障转移

可能的问题

  • AOF 重写机制可能会遇到内存不足或者内存碎片化的问题 。
  • 内存不足是指当 fork 出子进程时,操作系统会为子进程分配和主进程相同大小的内存空间,如果主进程占用的内存过大,可能导致内存不足而 fork 失败 。
  • 内存碎片化是指当 fork 出子进程时,操作系统会使用写时复制(copy-on-write)的技术,只有当主进程修改了内存页时,才会为子进程复制一个新的内存页 。但是如果主进程使用了大页(huge page)的特性,那么每次复制的内存页也会很大,可能导致内存碎片化而 fork 失败 。
  • 解决内存不足或者内存碎片化的问题的方法有以下几种 :

    • 增加物理内存或者虚拟内存
    • 优化 Redis 的数据结构和编码,减少内存占用
    • 关闭大页(huge page)的特性,避免复制过大的内存页
    • 使用 Redis 4.0 及以上版本,利用 rdb-preamble 特性,将 RDB 文件写入到 AOF 文件开头,以加快数据恢复速度

总结

  • AOF 重写是一种优化 Redis 的 AOF 持久化机制的方法,它可以压缩和优化 AOF 文件的内容,提高 Redis 的性能和稳定性
  • AOF 重写的原理是根据 Redis 进程内的数据生成一个新的 AOF 文件,只包含当前有效和存在的数据的写入命令
  • AOF 重写是通过 fork 出一个子进程来完成的,子进程会扫描 Redis 的数据库,并将每个键值对转换为相应的写入命令,然后写入到一个临时文件中
  • 在子进程进行 AOF 重写的过程中,主进程还会继续接收和处理客户端的请求,如果有新的写操作发生,主进程会将这些写操作追加到一个缓冲区中,并通过管道通知子进程
  • 子进程在完成 AOF 重写后,会将缓冲区中的写操作也追加到临时文件中,然后向主进程发送信号,通知主进程可以切换到新的 AOF 文件了
  • 主进程在收到子进程的信号后,会将缓冲区中的写操作再次追加到临时文件中(以防止在此期间有新的写操作发生),然后用临时文件替换旧的 AOF 文件,并关闭旧的 AOF 文件
  • AOF 重写机制有其优势和局限性,需要根据实际情况选择合适的触发方式,检查内存占用情况,关闭大页特性,使用 rdb-preamble 特性,定期检查 AOF 文件的大小和内容
Last modification:November 17, 2023
如果觉得我的文章对你有用,请随意赞赏