🗒️AOF (Append Only File)日志  
2024-9-11
| 2024-9-12
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
写前日志(Write Ahead Log,WAL):在实际写数据前,先把修改的数据记到日志文件中,以便故障时进行恢复。──例如数据库 redo log(重做日志)
写后日志(Write Behind Log,WAL):执行命令,把数据写入内存,然后才记录日志。──例如:Redis AOF 日志
传统数据库的日志,例如 redo log(重做日志),记录的是修改后的数据,而 AOF 里记录的是 Redis 收到的每一条命令,这些命令是以文本形式保存的。

AOF 日志的组成部分

我们以 Redis 收到“set testkey testvalue”命令后记录的日志为例,看看 AOF 日志的内容。其中,“*3”表示当前命令有三个部分,每部分都是由“undefined set”表示这部分有 3 个字节,也就是“set”命令。
notion image

为什么 AOF 采用写后日志?

简单来说,在保证 AOF 日志中命令的准确性的同时,避免额外的检查开销。写后日志会在命令执行成功后,才会被记录到日志当中,保证了正确性,不需要对命令做额外的语法检查。此外,在命令执行后才记录日志,不会阻塞当前的写操作。

AOF 存在的潜在风险:

  1. 如果命令执行完成后,来不及记录日志,就发生了宕机,有数据丢失的风险;
  1. AOF 虽然避免了对当前命令的阻塞,但可能会给下一个操作带来阻塞的风险。原因是 AOF 日志在主线程中进行,日志落盘时,可能会导致后续的操作无法执行。

AOF 中三种写回策略──配置项 appendfsync

  • Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘
    • 优点:数据安全性最高,每个写入操作都会被立即记录到磁盘。
    • 缺点:性能最差,因为每个写入都需要进行一次磁盘 I/O 操作。
  • Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
    • 优点:在性能和数据安全之间取得平衡。即使系统崩溃,最多也只会丢失一秒钟的数据。
    • 缺点:存在少量的数据丢失风险(最多一秒)。
  • No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,不主动进行同步,而是依赖于操作系统自身的缓存机制,由 OS 决定何时将缓冲区中的数据刷新到磁盘上。
    • 优点:性能最佳,因为完全依赖于 OS 的文件系统管理,不做额外的刷盘动作。
    • 缺点:数据丢失风险最大,如果系统崩溃,有可能会丢失大量未刷新的数据。

AOF 文件“瘦身”──AOF 重写机制

AOF 文件过大带来的性能问题:

  1. 文件系统本身对文件大小的限制;例如:FAT32 文件系统最大支持 4GB 的单个文件;
  1. 重启和故障恢复比较慢;
  1. 写入性能下降:频繁地将数据追加到一个非常大的AOF文件中,会导致1/0操作变得缓慢。
AOF 重写机制:AOF 重写并不是简单地复制原始的 AOF 文件,而是重新生成一份包含当前数据库状态的新文件。也就是说,读取数据库中的所有键值对,然后对每一个键值对用一条命令记录它的写入。

AOF 重写为什么能瘦身?

AOF 文件是以追加的方式,逐一记录收到的写命令的。当一条键值对被反复修改,AOF 文件会记录多条相应的命名。但实际上,我只需要最后执行的命令,也就是键值对的最新状态。因此,在重写的时候,是根据这个键值对当前的最新状态,为它生成对应的写入命令。
notion image
虽然 AOF 重写后,日志文件会缩小,但是,要把整个数据库的最新数据的操作日志都写回磁盘,仍然是一个非常耗时的过程。这时,我们就要继续关注另一个问题了:重写会不会阻塞主线程?

AOF 重写会阻塞吗?──重写的过程: “一次拷贝,两处日志”

和 AOF 日志由主线程写回不同,重写过程是由后台线程 bgrewriteaof 来完成的,避免阻塞主线程。
一个拷贝”就是指主线程 fork 出 bgrewriteaof 子线程时,会把主线程的内存拷贝一份给 bgrewriteaof 子进程。
两处日志:在重写的过程中,如果也有写操作,在 AOF 缓冲区和 AOF 重写缓冲区中,都会保存该操作。这个操作,保证了正在使用的 AOF 日志可以用于恢复,新的 AOF 重写日志是数据库的最新状态。
notion image
总结来说,每次 AOF 重写时,Redis 会先执行一个内存拷贝,用于重写;然后,使用两个日志保证在重写过程中,新写入的数据不会丢失。而且,因为 Redis 采用额外的线程进行数据重写,所以,这个过程并不会阻塞主线程。

📎 参考

 
  • Redis
  • RDB──Redis DataBaseredis 中 ZSet的范围查询的时间复杂度是多少
    Loading...
    目录