跳到主内容

Redis 持久化实测对比:RDB/AOF/混合持久化的恢复取舍与调参决策 ​

持久化配置是 Redis 里最容易被「抄默认值」的一块:默认 appendonly no,很多实例跑了几年实际是裸奔状态,一次意外重启就丢掉最后一次快照之后的全部数据;反过来也有人无脑开 appendfsync always,把写性能压到个位数 TPS 还找不到原因。持久化的本质是一个三角取舍:数据丢失容忍度、恢复速度、运行时性能,三者不可能同时拉满。这篇文章先把三种方案的取舍讲透,再带你完整走一遍恢复演练流程,最后给出按丢数据容忍度对号入座的调参清单。

三种方案一张表看清取舍 ​

维度RDB 快照AOF 日志混合持久化
数据安全丢失最后一次快照后的全部数据everysec 最多丢约 1 秒重写点后按 AOF 粒度丢失
文件体积小,二进制紧凑大,文本命令流接近 RDB,增量部分较小
恢复速度最快,直接还原内存最慢,逐条回放命令接近 RDB,仅增量需回放
运行时开销fork 时瞬时开销与写时复制内存持续的刷盘 IO 开销两者兼有,重写点前类似 RDB
适用场景灾备快照、可容忍分钟级丢失秒级丢失容忍的核心业务默认推荐,安全与速度兼得

RDB 是某个时刻的内存全量快照,由 bgsave 触发 fork 子进程生成,优点是文件小、恢复快、适合异地灾备,缺点是两次快照之间的数据在宕机时全部丢失。AOF 是写命令的追加日志,按 appendfsync 配置的频率刷盘,数据安全粒度细,但文件持续膨胀、恢复要逐条回放。混合持久化是 Redis 4.0 引入、aof-use-rdb-preamble 控制的折中方案:AOF 重写时,子进程先把当前内存状态以 RDB 格式写入文件头部,之后的增量写命令以 AOF 格式追加,恢复时头部的 RDB 段直接加载、增量段才需要回放,兼得两边长处。Redis 5.0 起该选项默认开启,Redis 7 的 Multi-Part AOF 把 AOF 拆成 base(RDB 格式)与 incr(增量命令)多个文件加一份 manifest 清单,重写机制更健壮,但「RDB 打底 + AOF 增量」的核心思路没有变。

恢复演练怎么做:方法、指标与相对结论 ​

「实测」不等于拍脑袋,一次规范的演练分四步。第一步,灌数据:用 redis-benchmark 或业务采样数据把实例填到目标规模,记录 INFO memory 的 used_memory。第二步,制造持久化文件:触发 BGREWRITEAOF 生成一份「干净」的重写后 AOF(混合模式下即 RDB 头加少量增量),另存一份纯 RDB 快照作对照。第三步,重启计时:SHUTDOWN 后重新拉起,用 time 命令记录 redis-server 从启动到日志输出 Ready to accept connections 的耗时,重复多次取稳定值。第四步,观测指标:恢复完成后立刻核对 dbsize 与灌数时一致、INFO persistence 各状态字段正常。

bash
# 灌入基准数据
redis-benchmark -h 127.0.0.1 -p 6379 -n 1000000 -d 128 -t set -q
# 生成干净的重写后 AOF,并核对状态
redis-cli BGREWRITEAOF
redis-cli INFO persistence | grep -E "aof_last_bgrewrite_status|rdb_last_bgsave_status"
# 演练:关停、计时重启、核对数据量
redis-cli SHUTDOWN NOSAVE
time redis-server /etc/redis/redis.conf
redis-cli DBSIZE

结论方面,相对关系是稳定且跨环境成立的:纯 AOF 回放恢复最慢,因为要把每条写命令重新执行一遍;RDB 加载最快;混合持久化的 base 段按 RDB 直接加载、只有重写点之后的增量需要回放,整体耗时接近纯 RDB。量级上,以十 GB 级数据、普通 SSD 实例为参考,纯 AOF 回放普遍在十分钟到几十分钟区间,RDB 加载在几分钟内完成。具体数字随数据构成、磁盘类型与实例规格差异很大,请以自己环境的演练结果为准——演练的意义不只是得出数字,更是确认「恢复流程本身走得通」。

调参清单:按丢失容忍度对号入座 ​

conf
# 场景一:可容忍分钟级丢失的缓存类业务,RDB 为主
save 3600 1 300 100 60 10000
stop-writes-on-bgsave-error yes

# 场景二:秒级丢失容忍的核心业务(推荐默认组合)
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
no-appendfsync-on-rewrite yes

# AOF 重写触发阈值
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 健壮性与可观测性
aof-load-truncated yes
aof-timestamp-enabled yes
lazyfree-lazy-user-del yes
lazyfree-lazy-expire yes

逐项说清取舍:appendfsync 三档中,always 每条命令都刷盘,性能代价最大,仅极端资金类场景考虑;everysec 每秒刷一次,是安全与性能的平衡点,宕机最多丢约一秒;no 交给操作系统决定,不建议。no-appendfsync-on-rewrite yes 表示 AOF 重写期间不再主动刷盘,牺牲少量安全性换取主线程不被磁盘 IO 卡住——重写本身就是 IO 大户,两个任务叠加容易互相拖累。auto-aof-rewrite-percentage 100 表示 AOF 体积比上次重写后翻倍即触发再次重写,min-size 64mb 防止小文件频繁重写;写入量巨大的实例可以适当调大 percentage,降低重写频率。aof-load-truncated yes 允许加载被截断的 AOF 尾部(崩溃瞬间的半条命令),提高可用性;aof-timestamp-enabled yes 在 AOF 中记录时间戳,便于按时间点定位与回放。

避坑总结 ​

  1. 盯住 fork 停顿。bgsave 与 AOF 重写都要 fork,内存越大停顿越久,INFO stats 的 latest_fork_usec 是最直接的观测指标;单实例内存建议控制在 10GB 量级以内,超大容量优先用集群分片拆解。
  2. 写时复制会推高内存峰值。fork 后父子进程共享内存页,但写入密集时写时复制会使实际内存用量显著上浮,极端时接近翻倍,容量规划要给 fork 窗口留余量,而不是卡着 maxmemory 配置。
  3. AOF 损坏先检查再修复。文件损坏时用 redis-check-aof 校验,确认后加 --fix 修复截断尾部;Redis 7 的多文件结构下对 manifest 清单文件执行检查即可覆盖整组文件,切勿直接删除文件了事。
  4. 恢复演练要制度化。备份文件躺在目录里不等于能恢复,定期在隔离环境拉起空实例执行完整恢复并计时,同时把 RDB 快照异地存放,才能真正兜住最坏情况。
  5. 主从节点不要一刀切。常见稳妥组合是主节点开 AOF 保住秒级数据、从节点承担 RDB 快照供灾备拉取,把 fork 压力分摊到非核心节点;只配一种持久化的实例至少要明确「丢了怎么办」的预案。

写在最后 ​

持久化配置没有唯一正确答案,正确的是与业务丢失容忍度对齐的那一组参数:缓存丢了可以重建,就用 RDB 求性能;交易数据丢一秒都疼,就 everysec 加混合持久化求安全;大多数业务直接采用「AOF 开启、everysec、混合持久化默认」的组合就能获得良好平衡。比参数更重要的,是把恢复演练变成季度例行事项——持久化方案的价值,最终体现在故障重启后的那份 Ready 日志里。

免责声明

本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。