AOF 以协议文本的方式,将所有对数据库进行过写入(不记录get等)的命令(及其参数)记录到 AOF 文件,以此达到记录数据库状态的目的。

要开启 AOF 功能,需要修redis.conf 中的下列参数:

// redis.conf
appendonly       yes               // 表示是否开启AOF(默认 no)
appendfilename   "appendonly.aof"  // AOF 文件的名称

AOF 文件格式

AOF 文件中的数据为RESP编码后的指令。举个例子,如果执行以下命令:

redis> RPUSH list 1 2 3 4
(integer) 4

redis> KEYS *
1) "list"

redis> RPOP list
"4"

那么有两条命令对数据库进行了修改:

RPUSH list 1 2 3 4
RPOP list

AOF 文件中被写入:

*2
$6
SELECT
$1
0
*6
$5
RPUSH
$4
list
$1
1
$1
2
$1
3
$1
4
*2
$4
RPOP
$4
list
*2
$4

SELECT 命令为 AOF 程序自动添加,表示数据所在的数据库,其他命令为执行的对数据库做更改的指令。

三种落盘策略

通过修改配置文件中appendfsync ,可以指定不同的写回硬盘的策略。支持的三种落盘策略分别为:

  • Always ,每次追加命令都立即 flush。

  • Everysec ,每隔一秒进行 flush。

  • NO ,不主动 flush,等待 OS 自动落盘。

需要注意的Everysec 的实现并不是严格每秒执行 flush。在该模式下Redis 会记录上次 flush 的时间,并且启动一个定时任serverCron每隔 100ms进行一次检查(如果系统负载高serverCron可能会被延迟执行),如果当前时间距离上次 flush 已经超过一秒,则进行 flush。

AOF 重写

AOF 文件中可能会有多条对同一个 key 进行修改的记录,此时只有最后一条是有效的。因此为了避免日志过大,Redis 会进行日志重写来减小日志体积。

AOF 重写时会创建一个新的文件,当重写完毕后再删除之前的日志,并将新的文件重命名为之前的日志名。

让人容易误解的一点是,AOF 重写并不依赖之前的日志文件。在执行AOF 重写时,类似于 RDB 快照,程序会遍历所有数据库中的所有数据,并将这些数据的保存执行写入日志。

AOF 后台重写

重写操作特别耗时,因此需要放到后台执行。Redis使用子进程来执行重写,因为父子进程共享内存,当内存被更改时发生COW,整个过程不需要加锁,如果使用线程在对内存进行修改时需要加锁。

后台重写时机

有两个配置项控制AOF重写的触发:

auto-aof-rewrite-min-size:表示运行AOF重写时文件的最小大小,默认为64MB。

auto-aof-rewrite-percentage:这个值的计算方式是,当前aof文件大小和上一次重写后aof文件大小的差值,再除以上一次重写后aof文件大小。也就是当前aof文件比上一次重写后aof文件的增量大小,和上一次重写后aof文件大小的比值。