Redis 的持久化设计一直存在两条主线:RDB 快照和 AOF 追加日志。它们并不是互斥的,甚至可以同时开启,但很多团队在选型时只关注“会不会丢数据”,忽略了恢复时间、fork 开销、文件膨胀和重写阻塞等更实际的运维问题。要从 RDB 与 AOF 之间做出合理选择,必须先理解两种机制在数据写入、保存和恢复阶段的根本差异。

RDB 的本质是某个时间点的全量内存数据快照,AOF 的本质是写命令的增量日志。下面从触发方式、写入流程、重写机制三个角度展开对比。
一、RDB与AOF的核心机制差异
RDB 持久化是把 Redis 内存中的数据集以二进制快照的形式写入磁盘,生成一个名为 dump.rdb 的文件。Redis 提供了两种生成 RDB 文件的方式:save 命令会在主进程直接执行快照,期间所有客户端请求都会被阻塞,一般只适合停机维护场景;bgsave 命令会 fork 一个子进程,由子进程负责写快照,主进程继续处理读写请求。自动触发通常依赖 save 配置项,例如 save 900 1 表示 900 秒内至少有 1 次写入就触发一次快照。由于 fork 使用了写时复制技术,子进程刚创建时与父进程共享同一块内存页,只有发生写入时才会复制被修改的页,因此 bgsave 不会一次性复制整个内存,但在写入频繁的场景下,fork 时机和页复制仍会带来一定的 CPU 与内存开销。
AOF 持久化则采用完全不同的思路:每执行一条写命令,Redis 就把该命令以 RESP 协议文本追加到 AOF 缓冲区,再根据刷盘策略写入 appendonly.aof 文件。刷盘策略由 appendfsync 控制:always 每次写命令都同步到磁盘,数据最安全但性能最差;everysec 每秒同步一次,最多可能丢失 1 秒数据,是性能与安全的常见平衡点;no 则交由操作系统决定何时刷盘,性能最好但崩溃时丢失数据最多。AOF 文件会随着写入不断增长,因此 Redis 提供 AOF 重写机制:fork 子进程根据当前内存数据生成一份新的 AOF 日志,替换旧文件,从而压缩体积。重写过程同样依赖写时复制,并且主进程在重写期间仍会把新写入命令追加到旧 AOF 缓冲区和重写缓冲区,直到子进程完成后把重写缓冲区内容追加到新文件再替换。
以下是一段常见的 Redis 持久化配置示例:
# RDB 自动触发条件 save 900 1 save 300 10 save 60 10000 # AOF 开启与刷盘策略 appendonly yes appendfsync everysec
从原理上看,RDB 关注的是某一时刻的完整状态,而 AOF 关注的是写操作的完整序列。前者适合需要快速恢复大量数据的场景,后者适合对数据完整性要求较高的场景,但二者都会引入额外的磁盘 I/O 和 fork 开销。
二、性能、数据安全与文件管理对比
数据丢失窗口是选型时最先考虑的指标。RDB 在两次快照之间的写入都依赖最后一次成功生成的快照,因此故障恢复后可能丢失的时间跨度取决于快照频率。如果配置为每 5 分钟快照一次,最坏情况会丢失 5 分钟的数据。AOF 在 appendfsync everysec 下通常只丢失 1 秒左右的数据,always 策略下理论上只丢失最后一次未完成同步的单条命令。但要注意,AOF 也不是绝对零丢失,如果操作系统或硬件发生崩溃,即使设置 always 也可能因为页缓存未落盘而丢失极少量数据。
恢复速度是另一个重要差异。RDB 文件是紧凑的二进制快照,Redis 启动时直接读入并重建整个内存数据集,恢复速度通常远快于 AOF。对于几个 GB 甚至更大的数据集,RDB 恢复可能只需要几十秒到几分钟,而 AOF 需要逐条执行写命令,恢复时间会随着文件大小线性增长。即使 AOF 重写可以压缩文件,但重写后的 AOF 仍然记录的是写命令序列,恢复时要一条条回放,无法达到 RDB 的直接加载速度。
文件体积方面,RDB 经过压缩,相同数据量下通常比 AOF 小很多。AOF 文件会记录每次写操作,即使对同一个 key 多次修改,旧命令也会保留在 AOF 中,直到重写才会清理。以频繁更新的计数器为例,RDB 只保存最终值,而 AOF 会积累大量中间状态命令。以下表格汇总了核心差异:
| 维度 | RDB | AOF |
|---|---|---|
| 数据丢失窗口 | 取决于快照频率,可能丢失几分钟 | everysec 通常最多丢 1 秒 |
| 恢复速度 | 快,直接加载二进制快照 | 慢,需要逐条回放命令 |
| 文件体积 | 较小,只保存最终状态 | 较大,积累历史写命令 |
| 写入性能影响 | fork 子进程时消耗 CPU 和内存 | 持续顺序写磁盘,fsync 影响延迟 |
| 故障风险 | 快照生成失败后无新备份 | 文件损坏可能影响恢复 |
性能影响不能只看平均吞吐量。RDB 在快照触发时通过 fork 创建子进程,如果 Redis 实例内存很大,fork 操作本身可能造成几十甚至几百毫秒的阻塞,写时复制期间的内存增长也可能拉高内存占用。AOF 虽然每秒同步,但在 everysec 模式下,主线程仍需要把数据写入 AOF 缓冲区,并处理重写缓冲,可能带来尾延迟抖动。可以通过 INFO persistence 查看最近一次 fork 状态和 AOF 写入情况,结合实际监控判断是否适合继续使用当前策略。
三、混合持久化与选型实践
Redis 4.0 引入了混合持久化机制,它在 AOF 重写时不再生成纯命令格式的 AOF 文件,而是先把当前内存数据以 RDB 格式写入 AOF 文件开头,再把重写期间新增的写命令以 AOF 格式追加到文件尾部。这样生成的 AOF 文件同时具备 RDB 加载快和 AOF 数据丢失少的优点。开启方式是在配置文件中加入 aof-use-rdb-preamble yes,同时保持 appendonly yes。
# 开启混合持久化 appendonly yes aof-use-rdb-preamble yes appendfsync everysec # 可选:保留 RDB 快照作为额外备份 save 3600 1 save 300 100 save 60 10000
混合持久化并不改变 AOF 的正常追加流程,只在重写时改变文件格式。因此日常写入性能与纯 AOF 基本一致,恢复时 Redis 会先加载文件头部的 RDB 部分,再回放尾部少量 AOF 命令,恢复速度显著快于纯 AOF。对于需要快速恢复且能接受秒级丢失的业务,混合持久化是当前最稳妥的默认选择。
不同业务场景的选型建议可以这样划分:纯缓存场景如果数据可以从数据库重新加载,关闭持久化能获得最低延迟,但要接受节点重启后缓存击穿的风险;对一致性要求较高但数据量不大的业务,可以只开 AOF,设置 everysec;数据量很大且能容忍几分钟丢失的离线分析或排行榜场景,可以只开 RDB,恢复快且文件小;核心交易、会话状态、消息队列积压等既要求低丢失又要求快速恢复的场景,推荐开启混合持久化,并在从节点上定期生成 RDB 作为异地备份。
四、常见误区与恢复策略
第一个常见误区是认为只要开启 AOF 就不会丢数据。实际上 appendfsync no 或操作系统崩溃时,AOF 仍可能丢失一部分尚未落盘的写命令。第二个误区是认为 RDB 快照恢复后数据一定是完整的,其实只要两次快照之间有写入,故障后这些写入就会丢失。第三个误区是认为 AOF 重写会长时间阻塞所有读写请求。实际上 Redis 使用子进程进行重写,主进程只在 fork 阶段和重写完成后的文件替换阶段有短暂阻塞,但如果写入压力极大,重写缓冲区的同步也可能造成延迟升高。
另一个常被忽略的点是:即使关闭了持久化,Redis 在进行主从全量同步时仍然会触发一次 RDB 快照,发送给从节点。因此“关闭持久化等于彻底没有磁盘写入”并不准确,如果从节点首次同步时主节点内存很大,仍会产生一次明显的 fork 和磁盘 I/O。
恢复数据时,如果 RDB 文件损坏,可以用 redis-check-rdb dump.rdb 检查;如果 AOF 文件损坏,可以用 redis-check-aof --fix appendonly.aof 尝试修复。修复过程会截断损坏位置之后的命令,可能导致部分数据丢失,因此生产环境应保留最近一次完好的备份文件,并优先从从节点或异地备份恢复。
# 检查 RDB 文件 redis-check-rdb /var/lib/redis/dump.rdb # 修复 AOF 文件 redis-check-aof --fix /var/lib/redis/appendonly.aof
无论选择哪种方案,都应该在测试环境中模拟主节点断电、磁盘写满、从节点升主等故障,验证实际恢复时间和数据丢失窗口是否符合业务要求。RDB 与 AOF 没有绝对优劣,只有与业务容灾目标匹配才是正确选择。