首页 / Redis 入门教程 / 19. 持久化 AOF

Redis 入门教程

19. 持久化 AOF

本教程共 40 篇 · 第 19 篇 · 更新于 2026-08-02

AOF追加日志appendonlyfsync重写BGREWRITEAOF

19. 持久化 AOF

RDB 用“快照”保住了某个时间点的全量数据,但两次快照之间的写入会在崩溃时丢失。如果你的业务要求“尽量不丢数据”,就需要另一种思路——AOF(Append Only File,追加日志)

AOF 的核心思想非常简单:把 Redis 执行过的每一条写命令按顺序记录下来。服务器重启时,只要把这些命令从头到尾再执行一遍,内存状态就能恢复到崩溃前的样子。

本节目标

  • 理解 AOF 与 RDB 的根本区别:记录“命令”而非“数据快照”。
  • 掌握 appendonly 开关与 appendfsync 三种落盘策略(always / everysec / no)的取舍。
  • 理解为什么 AOF 会越写越大,以及 AOF 重写(rewrite)如何压缩它。
  • 知道 AOF 文件损坏时如何用 redis-check-aof 修复。
  • 明确 AOF 在恢复速度与文件体积上的代价。

开启 AOF

默认情况下 AOF 是关闭的(appendonly no)。在 redis.conf 中改为 yes 即可开启:

appendonly yes

也可以运行时动态开启(但改动配置文件才能让重启后依然生效):

127.0.0.1:6379> CONFIG SET appendonly yes
OK
127.0.0.1:6379> CONFIG GET appendonly
1) "appendonly"
2) "yes"

开启后,每执行一条写命令(如 SETHSETLPUSH),Redis 都会把它追加到 AOF 缓冲区,再按 appendfsync 策略刷到磁盘。从 Redis 7 起,AOF 由一组文件组成(一个 base 基础文件 + 多个 incr 增量文件 + 一个 manifest 清单),默认目录为 appendonlydir,文件名前缀由 appendfilename 控制(默认 appendonly.aof)。

127.0.0.1:6379> SET user:1:name alice
OK
127.0.0.1:6379> HSET user:1 age 30 city bj
(integer) 2

这两条命令都会被追加进 AOF;重启后重放,便能还原出 user:1 这个哈希。

落盘策略:appendfsync

AOF 的可靠性,取决于“命令多久真正写到磁盘一次”——由 appendfsync 控制,有三种取值:

  • always:每条写命令都 fsync 到磁盘。最安全,最多丢一条命令;但每次写都伴随一次磁盘同步,性能最差。
  • everysec每秒 fsync 一次。默认值,也是绝大多数场景的推荐值——即便宕机,最多丢失约 1 秒的数据,同时性能很好。
  • no:不主动 fsync,交给操作系统决定何时刷盘。性能最好,但崩溃时可能丢失较多数据。
127.0.0.1:6379> CONFIG GET appendfsync
1) "appendfsync"
2) "everysec"

提示:appendfsync 选择 alwayseverysec 时,如果恰好有 BGSAVE 或 AOF 重写这类大量磁盘 I/O 的子进程在跑,Redis 在某些 Linux 配置下可能在 fsync() 上卡很久。配置项 no-appendfsync-on-rewrite no(默认)表示“重写期间照样 fsync”;若你更在意延迟、能接受最坏约 30 秒日志丢失,可改为 yes。一般保持默认即可。

为什么需要 AOF 重写

AOF 是“追加”模式,文件只会越来越大。设想你对同一个计数器执行了 100 次 INCR:AOF 里就记了 100 条命令,但其实最终状态只等价于一条 SET counter 100。文件既臃肿,恢复时也要重放 100 次。

**AOF 重写(rewrite)**就是用来解决这个问题的:Redis 读取当前内存数据,生成“能还原现状的最小命令集”写入新的 AOF 文件,然后原子替换旧文件。重写由子进程完成,主进程继续服务,期间的新写命令会同时进入旧 AOF 和一块内存缓冲,等子进程完成后追加进新文件,保证不丢数据。

触发方式有两种:

  1. 自动触发,由 auto-aof-rewrite-percentage(默认 100)和 auto-aof-rewrite-min-size(默认 64mb)控制:当 AOF 体积比上次重写后增长了 100% 且大于 64MB 时自动重写。
  2. 手动触发:
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started

AOF 文件损坏与修复

如果 AOF 在写入中途因断电、磁盘满而残缺,Redis 启动时会拒绝加载并报错。这时可用官方工具 redis-check-aof 修复:

redis-check-aof --fix appendonlydir/appendonly.aof.1.incr.aof

它会截断到最后一个完整命令,移除损坏尾部。注意:修复是以“丢弃损坏部分”为代价,因此该部分对应的写会丢失——但至少能让服务重新起来。

提示:AOF 还有一个“后悔药”场景:如果不小心执行了 FLUSHALL 把数据清空,只要 AOF 还没被重写过,可以立刻停服,用编辑器删掉 AOF 里最后一行的 FLUSHALL,再重启即可恢复到清空前的状态。一旦重写发生,这条命令已被合并进最小命令集,就救不回来了。

AOF 的优缺点

优点

  • 数据安全性高:默认 everysec 最多丢 1 秒;always 几乎不丢。
  • 文件是纯文本命令,可读、可手工排查,也便于做点“误删救援”。

缺点

  • 同等数据规模下,AOF 文件通常比 RDB 大得多。
  • 恢复时需要逐条重放命令,速度比 RDB 直接反序列化慢。
  • 重写虽在后台,但依然消耗 CPU 与 I/O。

所以 AOF 适合“对数据完整性要求高、能接受稍大文件与稍慢恢复”的场景,例如把 Redis 当作主存储或需要近实时持久化的业务。

小结

  • AOF 记录“写命令”而非“数据快照”,重启时重放命令恢复状态。
  • appendonly yes 开启;appendfsync 三档中 everysec 是默认且最实用的折中。
  • AOF 会随写入膨胀,BGREWRITEAOF / 自动重写把它压缩为“最小命令集”。
  • 文件损坏用 redis-check-aof --fix 截断修复;误执行 FLUSHALL 且未重写时可手工删除该行挽回。
  • 代价是文件大、恢复慢,但与 RDB 可同时开启互为补充。

常见误区

  • 误区一:无脑用 appendfsync always 求最安全。 它确实最多丢一条命令,但每次写都强制 fsync 到磁盘,吞吐下降明显,即便用 SSD 也要评估写放大。绝大多数场景 everysec 已足够安全且快得多。
  • 误区二:把 AOF 当普通文本随手改。 只有“未重写且误执行 FLUSHALL”这种特定情况,才能小心删掉最后一行救援。随意编辑、插入或截断会破坏 RESP 命令结构,导致整个 AOF 无法加载,只能用 redis-check-aof --fix 截断(仍丢数据)。
  • 误区三:AOF 一定比 RDB 大、恢复一定慢。 这是老印象。Redis 7+ 的混合持久化让 AOF 的 base 文件直接用紧凑的 RDB 格式,文件体积与恢复速度都大幅改善,二者不再是非此即彼。
  • 误区四:重写期间服务完全卡死。 重写由子进程在后台完成,主进程照常服务客户端;真正有成本的是 fork 瞬间与写时复制的额外 I/O,而非整段阻塞。

提示:本教程统一基于 Redis 8.x(最新稳定版)行文。补充说明:官方 redis.io 下载页另标 8.8 为 “Latest stable”,而 GitHub 上的最新发布 tag 为 8.10.0,二者同属 8.x 大版本,对 AOF 命令与配置项的讲述没有影响。