Redis 持久化机制对比:RDB / AOF / 混合持久化

jsntccc
jsntccc 正式会员正式会员认证极客认证极客
发布于 2026-10-20 21:12 ·1 浏览 ·4 回复
内容摘要

围绕 Redis 持久化,梳理 RDB、AOF 与混合持久化的差异和适用场景,给出配置修改、生效验证与在线切换步骤,并强调 RDB 恢复快但可能丢快照间数据、AOF 丢数据少但恢复慢、混合模式兼顾两者,需按版本开启并注意目录权限、fork 内存余量和 AOF 多文件备份等参数风险。

学完这篇你能得到一份可以直接照抄的 Redis 持久化配置方案:知道 RDB、AOF、混合持久化各自在什么场景下用,怎么改配置、怎么验证生效、怎么在线切换,以及哪些参数调错会出问题。

第一步:先分清三者到底在干什么

  • RDB:按时间间隔把内存数据生成一个二进制快照文件(默认 dump.rdb)。文件紧凑、恢复快,但两次快照之间的数据会丢。
  • AOF:把每条写命令追加到日志文件,重启时重放。丢数据少(最多丢 1 秒),但文件大、恢复慢。
  • 混合持久化:Redis 4.0 起支持。AOF 重写时,前半段用 RDB 格式存当前数据快照,后半段继续追加增量命令。恢复时先加载 RDB 部分再重放增量,兼顾了速度和安全性。

先确认你的版本,4.0 以下没有混合模式:

redis-server -v
redis-cli INFO server | grep redis_version

第二步:配置 RDB

打开 redis.conf,找到快照规则:

save 900 1        # 900 秒内至少 1 次写
save 300 10       # 300 秒内至少 10 次写
save 60 10000     # 60 秒内至少 10000 次写
dbfilename dump.rdb
dir /var/lib/redis
stop-writes-on-bgsave-error yes
rdbcompression yes

想彻底关掉 RDB,写 save ""(空字符串),不是注释掉——注释掉等于用默认规则。

注意:dir 是 RDB 和 AOF 共用的工作目录,必须存在且 redis 用户可写。另外每次 BGSAVE 会 fork 子进程,靠 copy-on-write 省内存;如果写入很猛,实际内存可能涨到 1.5~2 倍,maxmemory 要留出余量,否则会 OOM 或被 OOM Killer 干掉。

手动触发一次快照并确认:

redis-cli BGSAVE
redis-cli INFO persistence | grep rdb_last_bgsave_status

第三步:配置 AOF

appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

appendfsync 三选一,这是最关键的取舍:

取值丢数据性能
always几乎不丢最差,每条命令都 fsync
everysec最多 1 秒推荐,默认
no交给操作系统最快,可能丢几十秒

注意:Redis 7.0 起 AOF 改成多文件,放在 appenddirname "appendonlydir" 目录里,有一个 .manifest 清单文件。备份时不能只拷单个 .aof,要整个目录一起拷,否则恢复失败。

第四步:开启混合持久化

只需要加一行(Redis 5.0 起默认就是 yes):

aof-use-rdb-preamble yes

前提是 appendonly yes,AOF 关着这行没意义。

注意:混合模式生成的文件不能直接当 RDB 用,也不适合给老版本 Redis(< 4.0)读取,降级前先 BGREWRITEAOF 或在低版本上重建。

第五步:验证与在线调整

不用重启就能改的参数,用 CONFIG SET:

redis-cli CONFIG SET appendfsync everysec
redis-cli CONFIG SET auto-aof-rewrite-percentage 100
redis-cli CONFIG REWRITE          # 把改动写回 redis.conf,否则重启丢失
redis-cli INFO persistence        # 看 aof_enabled / aof_last_bgrewrite_status
redis-cli BGREWRITEAOF            # 手动重写压缩 AOF

运行时从 RDB 切到 AOF:

redis-cli CONFIG SET appendonly yes

这条命令会自动触发一次 AOF 重写,把当前内存写成初始 AOF。切换后务必执行 CONFIG REWRITE,并在业务低峰做,重写期间 fork 会短暂卡顿。

注意:不要在生产上反复来回切持久化方式。切换过程有 fork 开销和磁盘 IO 峰值,容易顶到 CPU 打满。

第六步:按场景选

  • 纯缓存,丢了能回源:可以关掉持久化,或者只留 RDB 低频快照。
  • 允许丢几分钟数据,追求恢复速度:RDB 就够,重启加载快。
  • 订单、余额、会话这类不能丢:AOF + everysec,或直接上混合持久化。
  • 数据量大又要求快速恢复:混合持久化,这就是它的设计目的。

小结

  1. RDB 快但会丢窗口数据,AOF 稳但文件大恢复慢,混合持久化是默认推荐。
  2. appendfsync everysec 是绝大多数业务的正确选择,别为了"绝对不丢"上 always。
  3. RDB 关闭用 save "",不是删掉 save 行。
  4. CONFIG SET 改完必须 CONFIG REWRITE,否则重启回到旧配置。
  5. Redis 7.0 的 AOF 是多文件目录,备份要整目录拷。
  6. fork + copy-on-write 会放大内存,maxmemory 一定要留余量。
本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-912.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 4

玄墨染
玄墨染 正式会员正式会员认证极客认证极客 1楼 2026-10-20 21:19

这套配置可以直接照抄,但有三个线上最容易翻车的点帖子里没写透,补上。

1. AOF 开着时,RDB 就是摆设。 Redis 启动恢复是有优先级的:appendonly yes 时只重放 AOF,dump.rdb 完全不读。所以“我明明有快照怎么数据还是旧的”——大概率是 AOF 里残留了旧数据。要验证恢复走了哪条路,看启动日志:纯 AOF 是 DB loaded from append only file,混合模式是 Reading RDB preamble from AOF file,纯 RDB 是 DB loaded from disk。这行日志比 INFO persistence 更直接。

2. 在线切换别直接 CONFIG SET 完就完事。

redis-cli CONFIG SET appendonly yes   # 立即触发一次全量 AOF 重写,大实例有 IO 尖峰
redis-cli CONFIG REWRITE              # 把改动写回 redis.conf,否则重启就回滚了

CONFIG REWRITE 这步最常被漏,现象是“我明明开了 AOF,重启后又变回去了”。切换建议低峰做,几十 G 的实例重写期间磁盘 IO 会明显抖动。

3. fork 失败比内存翻倍更常见。 除了帖子里说的 maxmemory 留余量(按物理内存 60% 左右设比较稳),Linux 上一定要确认 vm.overcommit_memory=1,否则 BGSAVE 会直接报 Can't save in background: fork: Cannot allocate memory,而这个错误在业务侧看起来就是“写入突然全部失败”。

延伸一个坑:stop-writes-on-bgsave-error yes 在磁盘写满时会让 Redis 变成只读并返回 MISCONF 错误,很多人第一反应是查业务代码,其实是磁盘满了。监控里把 rdb_last_bgsave_status 和磁盘剩余空间一起盯,能省不少排查时间。

最长的电影
最长的电影 正式会员正式会员 #1077 2楼 2026-10-20 21:28
玄墨染:这套配置可以直接照抄,但有三个线上最容易翻车的点帖子里没写透,补上。 **1. AOF 开着时,RDB 就是摆设。** Redis 启动恢复是有优先级的:`a…

这三条都对,尤其第 1 条应该是排障第一顺位;补充一下反方向的两个坑。

AOF 为空、损坏时,Redis 不会回退到 RDB。 因为 appendonly yes,旧版 Redis 发现 AOF 文件不存在或为空时仍会正常启动,得到一个空实例;你看到的现象就是“数据全没了但进程健康”。所以要记住:AOF 开启后,dump.rdb 只剩冷备价值。备份策略应改为定期 BGSAVE 并复制出 dump.rdb,或整目录打包 appendonlydir,绝不能只依赖线上那一份。另外 aof-load-truncated 默认 yes,允许截断的尾部继续启动;改成 no 时会直接拒绝启动,需要手动 redis-check-aof --fix。

反向切换同样要三思。执行 CONFIG SET appendonly no 时,Redis 不会删掉旧 AOF 文件;重启后是否又读回它,取决于 conf 里的 appendonly。关闭 AOF 后,立刻执行一次 BGSAVE,否则最后几秒的写操作只存在于内存中。

THP 是 fork 的隐形放大器。红帽系默认开启透明大页,COW 以 2MB 页为单位复制,大实例执行 BGSAVE 时,内存上涨会比预期凶得多。建议执行 echo never > /sys/kernel/mm/transparent_hugepage/enabled 并写进开机脚本,再用 INFO stats 的 latest_fork_usec 盯 fork 耗时,超过 1 秒就该警惕了。

补充一句:vm.overcommit_memory=1 在容器里不算生效,得在宿主机设或加 --vm.overcommit_memory=1,这点 Docker 部署的人经常踩。

ipzh
ipzh 正式会员正式会员认证极客认证极客 钻石卡会员钻石卡会员 #1078 3楼 2026-10-20 21:33
最长的电影:这三条都对,尤其第 1 条应该是排障第一顺位;补充一下反方向的两个坑。 **AOF 为空、损坏时,Redis 不会回退到 RDB。** 因为 `appendo…

「备份改成定期的 BGSAVE + 复制 dump.rdb」这条我完全同意,但还可以再补一步:备份文件本身必须真的验一次能不能恢复,否则你只能确认备份是“生成成功”,无法确认它“恢复得回来”。

验证恢复有两个层次。比较简单的是 DEBUG RELOAD:它会把当前数据按持久化文件重新加载一遍,能完整走通恢复流程。但从 7.0 起,这个命令默认被禁用;执行时会报 DEBUG command not allowed,需要临时把 enable-debug-command 设成 yes(或 local)再执行,验证完记得改回去。更稳妥的做法是:把整份备份放到一台隔离实例上实际启动,再用 redis-check-rdb / redis-check-aof 检查一遍文件完整性,确认能启动、DBSIZE 对得上之后,才算完成验证。

另外,前面提到的 redis-check-aof --fix 在 7.0 的多文件 AOF 下有一点需要注意:参数要指向 appendonlydir 里的 .manifest,不能指向单个文件;而且 --fix 的语义是“截断到最后一个完整命令”,尾部那一截命令会直接丢掉。所以修之前先把整个目录压缩打包留一份。如果想事后定位到底丢失到哪一刻,可以开 aof-timestamp-enabled yes,这样每条命令会带时间戳,排障时很有用。

再补一个针对容器环境的细节:容器里的 maxmemory 要按 cgroup 限制来算,不能按宿主机物理内存来算;否则“60% 留余量”那套算法在容器里会直接把上限算到宿主机内存的大小,OOM Killer 仍然会来。

最后,反向切断 AOF 之后先不要急着删除 appendonlydir,把它改名保留一两个备份周期,确认无误后再清理。

ipzh.com域名网 Lv3
xiaoxin
xiaoxin 正式会员正式会员认证极客认证极客 #1079 4楼 2026-10-20 21:40
ipzh:「备份改成定期的 `BGSAVE` + 复制 `dump.rdb`」这条我完全同意,但还可以再补一步:**备份文件本身必须真的验一次能不能恢复**,否则你只能确…

结论:你补的验证闭环和容器细节都对,但 DEBUG RELOAD 这句要修正一下——它根本不读磁盘上的 dump.rdb。

DEBUG RELOAD 走的是"内存里 RDB 序列化 → 内存里再反序列化"(rdbSaveRio 到 rio buffer,再 rdbLoadRio),既不写盘也不读盘。所以它能验证的是"当前数据集干净、能完整走通 RDB 编解码路径",验证不了备份文件是否被截断、拷贝过程有没有损坏——而这恰恰是备份环节最容易出问题的地方。真要验文件,只有你说的第二层:隔离实例启动 + redis-check-rdb。想快速拿一份文件来验,还有条更省事的路:redis-cli --rdb /tmp/verify.rdb 走复制通道从主库拉一份完整 RDB,不需要碰 debug 命令。

再纠一个操作细节:enable-debug-command 是 immutable 配置,CONFIG SET 改不了,只能改配置文件重启。所以"临时开一下、验完改回去"实际是两次重启,生产上基本不可行,这也更说明隔离实例那条路才是正解。

aof-timestamp-enabled 补个反作用:开了之后 AOF 里会混入 #TS: 注释行,7.0 以下版本解析不了,将来降级或拿老版本 redis-check-aof 去修会直接失败。跨版本回放有需求的实例建议先别开。容器 maxmemory 那条同意,具体取值:cgroup v2 看 /sys/fs/cgroup/memory.max,v1 看 memory/memory.limit_in_bytes,别用 free -g。

最后,appendonlydir 改名保留的习惯很好,配套再做一步:确认 appendonly no 已经 CONFIG REWRITE 落盘,否则下次重启照样把旧目录读回来。

嘻嘻 Lv1