Redis 的 AOF(Append Only File,仅追加文件)持久化的运行机制,简单来说:AOF 通过记录 Redis 执行的所有写命令 **(如 SET、HSET、LPUSH 等)到文本日志文件中,Redis 重启时,会逐行重放 AOF 文件中的命令,从而恢复内存数据 **。与 RDB 的 "快照式" 持久化不同,AOF 是 "命令式" 的持久化,能最大程度保证数据不丢失,下面从核心运行流程、同步策略、重写机制、恢复流程、配置等方面详细拆解。
一、AOF 的核心运行流程
AOF 的工作分为三个核心阶段 ,整个流程围绕 "减少磁盘 IO 开销、保证数据安全性" 设计,具体如下:
1. 阶段 1:命令追加(Append)
-
当客户端发送写命令(只读命令如 GET 不会记录)时,Redis 先执行命令,更新内存中的数据;
-
然后将该命令的协议格式字符串追加到 **AOF 缓冲区(aof_buf)** 中(而非直接写入磁盘)。
为什么用缓冲区?如果每次写命令都直接写入磁盘,频繁的磁盘 IO 会严重降低 Redis 性能,缓冲区可以批量写入,减少 IO 次数。
示例:执行
SET name tom,AOF 缓冲区会追加类似这样的协议字符串:bash*3\r\n$3\r\nSET\r\n$4\r\nname\r\n$3\r\ntom\r\n(Redis 的 RESP 协议格式,包含命令参数数量、参数长度、参数内容,确保命令可重放)
2. 阶段 2:文件写入(Write)与同步(Sync)
Redis 会根据配置的AOF 同步策略 ,将 AOF 缓冲区中的数据写入(write)到 AOF 文件的内核缓冲区,再同步(fsync)到磁盘。
- 写入(write):将数据从用户态缓冲区(aof_buf)写入内核态缓冲区(操作系统的页缓存),这一步是内存操作,速度快;
- 同步(sync,即 fsync 系统调用):将内核缓冲区的数据强制刷入磁盘,这一步是磁盘 IO 操作,速度慢。
关键:AOF 的同步策略决定了数据安全性和性能的平衡,这是 AOF 运行的核心配置。
二、AOF 的同步策略(核心配置)
Redis 提供了三种 AOF 同步策略,通过redis.conf中的appendfsync参数配置,不同策略对应不同的数据安全性和性能开销:
| 同步策略 | 配置值appendfsync |
执行逻辑 | 数据安全性 | 性能开销 | 适用场景 |
|---|---|---|---|---|---|
| 总是同步 | always |
每次写命令追加到缓冲区后,立即执行fsync,将数据刷入磁盘 |
最高(仅丢失故障瞬间的命令) | 最大(频繁磁盘 IO,Redis 性能下降) | 金融交易等对数据安全性要求极高的场景 |
| 每秒同步 | everysec(默认) |
每秒执行一次fsync,将缓冲区中的数据刷入磁盘(异步执行) |
较高(最多丢失 1 秒数据) | 适中(平衡性能与安全) | 绝大多数生产环境场景 |
| 不主动同步 | no |
Redis 仅负责将数据写入内核缓冲区,由操作系统决定何时fsync刷入磁盘(通常 30 秒) |
最低(可能丢失大量数据) | 最低(Redis 性能最优) | 测试环境、对数据丢失不敏感的场景 |
注意:
everysec是默认且推荐的策略,它在性能和数据安全性之间做了最优平衡 ------ 即使fsync阻塞,也只会阻塞异步线程,不会影响 Redis 主进程处理请求。
三、AOF 的重写机制(解决文件膨胀问题)
AOF 会不断追加写命令,随着时间推移,文件会变得越来越大(比如反复执行INCR counter,AOF 会记录所有 INCR 命令,而实际只需记录SET counter 1000即可)。为了解决这个问题,Redis 引入了 **AOF 重写(Rewrite)** 机制:
1. 重写的核心原理
AOF 重写不是对旧的 AOF 文件进行编辑或压缩,而是Redis 通过遍历当前内存中的数据,生成一组 "最简的写命令"(相当于重建数据的命令集),替换旧的 AOF 文件。
- 示例:内存中有
counter=1000,旧 AOF 记录了 1000 次INCR counter,重写后只记录SET counter 1000,文件体积大幅缩小。
2. 重写的触发方式
分为手动触发 和自动触发两种:
(1)手动触发:BGREWRITEAOF命令(推荐)
bash
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started # 后台重写已启动
- 执行逻辑:Redis 主进程
fork一个子进程,由子进程负责生成新的 AOF 文件,主进程继续处理客户端请求(期间新的写命令会同时追加到旧 AOF 文件和AOF 重写缓冲区); - 子进程完成后,主进程会将重写缓冲区中的命令追加到新 AOF 文件,然后用新文件替换旧文件(原子操作)。
(2)自动触发:配置重写条件
bash
# 当AOF文件大小增长超过指定百分比(默认100%,即翻倍)时触发重写
auto-aof-rewrite-percentage 100
# 触发重写的最小AOF文件大小(默认64MB,避免小文件频繁重写)
auto-aof-rewrite-min-size 64mb
- 示例:如果当前 AOF 文件是 64MB,当文件增长到 128MB(翻倍)时,自动触发重写。
3. 重写的优势
- 减小 AOF 文件体积,节省磁盘空间;
- 重放命令时,执行的命令数更少,数据恢复速度更快。
四、AOF 的数据恢复流程
当 Redis 重启时,会优先加载 AOF 文件(如果 AOF 开启)恢复数据,流程如下:
- Redis 启动时,检查是否开启 AOF(
appendonly yes); - 如果开启,查找
appendfilename指定的 AOF 文件(默认appendonly.aof); - 如果文件存在,Redis 逐行读取并执行 AOF 文件中的写命令,将数据恢复到内存;
- 如果文件不存在或 AOF 未开启,才会加载 RDB 文件(如果有);
- 加载完成后,Redis 开始接受客户端请求。
异常处理:AOF 文件损坏
如果 Redis 异常关闭(如断电),可能导致 AOF 文件末尾的命令不完整,Redis 启动时会报错。此时可使用 Redis 提供的redis-check-aof工具修复:
bash
# 修复AOF文件(会删除末尾不完整的命令)
redis-check-aof --fix /var/lib/redis/appendonly.aof
五、AOF 的核心配置(redis.conf)
除了上述的同步策略和重写配置,AOF 还有以下关键配置:
bash
# 开启AOF持久化(默认no,需手动改为yes)
appendonly yes
# 指定AOF文件名
appendfilename "appendonly.aof"
# 指定AOF文件的保存目录(与RDB的dir配置相同)
dir /var/lib/redis
# AOF同步策略(默认everysec)
appendfsync everysec
# 重写期间是否暂停同步AOF(默认no,保证数据安全性)
no-appendfsync-on-rewrite no
# 开启AOF与RDB混合持久化(Redis 4.0+支持,推荐开启)
aof-use-rdb-preamble yes
混合持久化(
aof-use-rdb-preamble yes):AOF 文件的开头是 RDB 的快照数据,后续是增量的 AOF 命令。这样既拥有 RDB 的快速恢复速度,又拥有 AOF 的实时数据安全性。
六、AOF 与 RDB 的核心对比(补充)
| 特性 | AOF | RDB |
|---|---|---|
| 持久化方式 | 记录写命令(追加式) | 记录内存快照(全量式) |
| 数据安全性 | 高(最多丢失 1 秒数据,always 策略无丢失) | 低(周期性快照,丢失快照间数据) |
| 文件体积 | 大(命令追加,重写后缩小) | 小(二进制压缩) |
| 恢复速度 | 较慢(重放大量命令) | 较快(直接加载快照) |
| 性能开销 | 较低(缓冲区 + 异步同步) | 较高(fork 子进程,大内存 fork 卡顿) |
总结
关键点回顾
- AOF 的核心运行逻辑:写命令→追加到 AOF 缓冲区→根据同步策略写入 / 同步到 AOF 文件→重写机制压缩文件→重启时重放命令恢复数据。
- 同步策略 :有
always(最安全)、everysec(默认推荐)、no(最快)三种,平衡数据安全与性能。 - 重写机制 :通过
BGREWRITEAOF(手动)或配置条件(自动)触发,生成最简命令集的新 AOF 文件,解决文件膨胀问题。 - 数据恢复 :Redis 启动时优先加载 AOF 文件,文件损坏可通过
redis-check-aof修复。 - 生产环境推荐 :开启 AOF+RDB 混合持久化(
aof-use-rdb-preamble yes),兼顾恢复速度和数据安全性。
简单来说,AOF 的运行是 "记录命令→同步文件→压缩文件→重放恢复" 的闭环,是 Redis 保证数据高可用性的核心机制之一。