RDB 和 AOF 有什么区别?怎么选?

进阶高频对比约 6 分钟读完

一句话回答

RDB 是某一时刻的内存快照:fork 一个子进程,借助写时复制把数据写成紧凑的二进制文件,恢复快,但会丢失最后一次快照之后的数据。AOF 把每条写命令追加到日志文件里,按 appendfsync 刷盘,默认 everysec 通常最多丢 1 秒左右的数据,但文件大、恢复慢,需要定期重写压缩。生产中常用混合持久化:AOF 重写时先写一份 RDB 格式的快照,之后只追加增量命令,兼顾恢复速度和数据安全。

详细解析

RDB:快照

  • 执行 BGSAVE,或者按 save 配置自动触发。比如 save 3600 1 300 100 60 10000 表示 3600 秒内至少 1 次修改、300 秒内至少 100 次、60 秒内至少 10000 次,满足任意一条就生成快照
  • SAVE 在主线程里生成快照,会阻塞所有请求,生产环境不用
  • 主从全量同步时,主节点也会生成 RDB 发给从节点

fork + 写时复制:

文本
fork 之后:父子进程共享同一份物理内存页,只复制了页表
子进程:遍历内存写 RDB 文件,看到的始终是 fork 那一刻的数据
父进程:继续处理请求;要修改某个内存页时,操作系统先复制这个页,父进程改的是副本

这样既能得到一致的快照,又不用暂停服务。代价有两个:

  • fork 要复制页表,这一步在主线程里同步执行,内存越大耗时越长,期间所有请求都会被阻塞
  • 快照期间写入越多,被复制的页越多,最坏情况下内存占用接近翻倍。Linux 的透明大页(THP)会让每次复制的单位从 4KB 变成 2MB,所以官方建议关闭 THP

AOF:追加写命令

每执行完一条写命令,就把它追加到 AOF 缓冲区,再按 appendfsync 的配置写入磁盘:

取值 行为 数据安全
always 每次写入都 fsync 最安全,性能最差
everysec(默认) 后台线程每秒 fsync 一次 通常最多丢 1 秒左右的数据
no 只写入操作系统缓存,何时刷盘由操作系统决定 可能丢失较多数据

Redis 是先执行命令、再写日志,和 MySQL 的 WAL 正好相反:命令执行成功了才记录,不会把错误的命令写进日志,写日志也不会拖慢当前命令的执行;代价是命令执行完、还没写进日志时宕机,这条命令就丢了。

AOF 重写:同一个 key 被修改 100 次,AOF 里就有 100 条命令,但恢复时只需要最终的值。重写时 fork 子进程,直接根据当前内存中的数据生成最精简的命令,不读取旧的 AOF 文件。可以手动执行 BGREWRITEAOF,也可以配置为文件比上次重写后增长一倍、且超过 64MB 时自动触发(auto-aof-rewrite-percentage 100、auto-aof-rewrite-min-size 64mb)。

重写期间的新命令怎么处理:Redis 7.0 之前,主进程把新命令额外写进一块重写缓冲区,子进程完成后再追加到新文件;7.0 引入了 Multi Part AOF,AOF 被拆成一个基础文件和若干个增量文件,重写时新命令直接写入新的增量文件,不再需要这块缓冲区。

混合持久化

aof-use-rdb-preamble yes(默认开启)时,AOF 重写生成的基础部分是 RDB 格式,之后的增量还是 AOF 命令。恢复时先加载 RDB 部分,再重放少量增量命令,比重放完整的 AOF 快得多,丢失的数据也很少。

同时开启 RDB 和 AOF 时,重启后优先用 AOF 恢复,因为它的数据更完整。

对比和选择

RDB AOF
内容 某一时刻的数据快照(二进制) 写命令日志
数据丢失 上次快照之后的所有修改 everysec 下通常最多 1 秒左右
文件大小 小,适合备份和传输 大,需要定期重写
恢复速度 快,直接加载 慢,要重放命令(混合持久化后大幅改善)
对性能的影响 平时几乎没有,fork 时短暂阻塞 每次写入都要追加日志
默认状态 开启 关闭,需要配置 appendonly yes
  • 纯缓存,数据随时可以从数据库重建:可以关闭持久化,或者只保留 RDB,让重启后预热更快
  • 不想丢数据,比如存了只在 Redis 里才有的会话、计数:开启 AOF(everysec)+ 混合持久化,再定期把 RDB 文件备份到其他机器
  • 持久化不等于高可用,机器坏了,数据还留在这台机器上,要配合主从复制,见 主从、哨兵和 Cluster

面试官可能追问

主节点关闭了持久化,会有什么风险?

如果主节点没开持久化,又配置了进程挂掉后自动重启,它重启后是一个空实例,从节点会照常和它同步,结果把自己的数据也清空了。所以开了主从复制时,主节点要么开启持久化,要么不要让它自动重启,而是先由哨兵把从节点提升为主节点。

AOF 文件损坏了怎么办?

最常见的是宕机时最后一条命令只写了一半。Redis 默认 aof-load-truncated yes,发现文件末尾不完整时会丢掉这一截并继续启动,同时打印日志。如果是文件中间损坏,Redis 会拒绝启动,这时先备份文件,再用 redis-check-aof --fix 修复,它会截掉损坏位置之后的内容,修复前最好先确认会丢掉哪些数据。

fork 会阻塞多久?怎么减小影响?

fork 要复制页表,耗时和实例的内存大小正相关,可以从 INFO stats 里的 latest_fork_usec 看到上一次 fork 花了多少微秒。减小影响的办法:控制单个实例的内存,数据多就用 Cluster 拆成多个小实例;关闭透明大页;给机器留出足够的内存应对写时复制;避免在业务高峰手动触发 BGSAVE 和 AOF 重写。

易错点

  • BGSAVE 不是完全不阻塞,fork 的那一刻主线程会卡住
  • everysec 的"丢 1 秒"是大致范围,磁盘繁忙导致 fsync 变慢时,丢失的数据可能更多
  • AOF 重写不读旧的 AOF 文件,而是根据当前内存数据生成
  • AOF 默认是关闭的

AI 模拟面试官

用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮

登录后就可以和 AI 面试官对练,面试记录也会保存下来。登录

这道题你掌握了吗?

选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。

学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。