混合持久化:配置与取舍
纯 RDB 丢数据窗口大,纯 AOF 恢复慢,混合持久化把两者拼在一起:快照保证恢复速度,增量日志保证数据完整。本文讲清 Redis 7 中混合持久化的结构、配置、验证方法,以及什么时候不该用它。
一、三种持久化形态对比
选持久化方案,本质上是在丢失窗口、恢复速度与可维护性之间做权衡:
| 形态 | 丢失窗口 | 恢复速度 | 文件可读性 |
| --- | --- | --- | --- |
| 纯 RDB | 两次快照之间全部 | 快 | 不可读 |
| 纯 AOF(everysec) | 约 1 秒 | 慢,逐条重放 | 文本可读 |
| 混合持久化 | 约 1 秒 | 快(RDB 加载 + 少量重放) | 不可读 |
混合持久化不是独立开关,而是 AOF 体系下的文件组织方式,由 aof-use-rdb-preamble 控制。
二、结构:base 与 incr 的分工
Redis 7 开启 AOF 后,数据目录中的 appendonlydir 包含三类文件:
appendonlydir/
├── appendonly.aof.manifest
├── appendonly.aof.1.base.rdb
└── appendonly.aof.1.incr.aof
base 是上次重写生成的全量基准,aof-use-rdb-preamble yes 时为 RDB 格式;incr 记录基准之后的所有写命令;manifest 登记当前生效的文件组合与顺序。加载时先解析 base(走 RDB 路径),再重放 incr。数据量集中在 base、增量很短的情况下,恢复耗时以 base 的加载为主,这正是混合格式快的原因。
三、配置与验证
appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
aof-use-rdb-preamble yes
appendfsync everysec
aof-use-rdb-preamble 自 Redis 5.0 起默认 yes,一般不需要动。验证配置是否生效有两个办法:看 base 文件后缀是否为 .rdb;或查看启动日志,7.0 会出现 "Reading RDB base file on AOF loading" 字样,说明按混合方式加载。
其余几项的分工值得逐条说清:
appendonly yes是总开关。7.0 起它不再只是"多写一个文件",而是启用整个多部分目录;关闭后appendonlydir仍留在磁盘上,只是不再被读取。appendfilename "appendonly.aof"在多部分结构里只作为文件名的前缀。实际生成的是appendonly.aof.1.base.rdb、appendonly.aof.1.incr.aof与appendonly.aof.manifest,改这个值等于换一套文件命名,迁移时要前后一致。appenddirname "appendonlydir"是 7.0 新增项,指定多部分文件所在的子目录,路径相对于dir。它让 AOF 与 RDB 得以共存于同一数据目录而不互相干扰,旧的单文件appendonly.aof不会与之混淆。appendfsync everysec决定 incr 的落盘节奏,也是丢失窗口的直接来源:always每条命令都 fsync,最安全但吞吐会掉一个量级;no交给操作系统回写,通常几十秒才落盘。混合持久化只改变 base 的格式,不影响 incr 的 fsync 语义,所以"混合 = 丢 1 秒"这个结论只在everysec下成立。
注意:改动
aof-use-rdb-preamble后需要触发一次重写(BGREWRITEAOF)才会按新格式生成 base,已有的旧文件不会立刻变化。
四、什么时候关掉混合
把 aof-use-rdb-preamble 设为 no 的理由不多,但真实存在:
- 需要直接审计 AOF 内容。 no 时 base 是命令文本,可以 grep、diff,教学与排障场景有用;yes 时只能借助 redis-check-aof 或加载后查看。
- 需要降级到 4.0 以下版本。 混合格式自 4.0 引入,更老的版本无法解析;多部分目录结构更是 7.0 才有。降级前应先用
SAVE生成纯 RDB 再迁移。 - 极端的工具链依赖。 自定义解析器、离线分析脚本对文本格式有依赖的场景。
除此之外,混合格式在安全性与速度上都不劣于纯文本 AOF:base 的 RDB 部分有 CRC64 校验,incr 部分照常校验截断,生产默认开启是合理的。
五、一个具体的故障场景
理解取舍最有效的方式是看一次真实事故。某实例 32gb 内存,appendfsync everysec,混合格式,磁盘使用率 91%:
- 凌晨
BGREWRITEAOF被触发,子进程开始写 32gb 的新 base,磁盘剩余空间只够写到 70%; - 写盘返回
ENOSPC,子进程异常退出,aof_last_bgrewrite_status变成 err; - 父进程仍在向 incr 追加,磁盘彻底写满,
write失败后 Redis 依据stop-writes-on-bgsave-error的行为停止接受写命令; - 业务侧表现为所有写请求返回
MISCONF Redis is configured to save RDB snapshots...,读请求正常。
事后复盘有两个关键点。第一,混合持久化把一次重写变成"写一份接近数据集大小的文件",阶段内的磁盘增量需求比纯 AOF 追加更集中,容量水位必须按"当前文件 + 新 base"预留,而不是按平均增长量估算。第二,故障期间读请求仍然可用,如果应用层把写异常当成整体不可用而直接熔断,反而是把影响放大了。
正确的止损顺序是:先扩容或清理磁盘,让子进程能重试成功;确认 aof_last_bgrewrite_status:ok 后再恢复写入;最后再调整 auto-aof-rewrite-min-size 与磁盘告警阈值,避免下次同样的时间点再踩一次。
六、恢复速度验证方法
用同一份数据分别测两种格式的加载时间,结论才有说服力:
# 启动后观察日志中的加载耗时
grep "DB loaded" /var/log/redis/redis-server.log
# DB loaded from append only file: 41.236 seconds
实测中 RDB 格式 base 的加载速度通常是纯命令重放的数倍到数十倍,数据集越大差距越明显。把这个数字记进实例的 RTO 评估表,是容灾规划的基础输入:几十 GB 的实例,两种格式的恢复时间可能差出小时级。
七、选型建议
把决策按场景分档,比笼统地说"用混合"更有操作性:
- 纯缓存、可回源:持久化不是刚需,
appendonly no加偶尔的 RDB 备份即可。重启后缓存空了会带来回源压力,比持久化开销更值得关注。 - 会话、排行榜等可重建但重建成本高的数据:混合持久化 +
everysec。丢失 1 秒可以接受,恢复速度直接影响故障恢复时长。 - 订单状态、幂等令牌等不可丢数据:持久化只是兜底,Redis 不该作为唯一存储。
appendfsync always能把窗口压到单条命令,但吞吐下降明显,写热点场景基本不可行。 - 跨版本兼容或需要审计日志:主动关闭 preamble,接受恢复变慢,换取 base 的文本可读性。
每个选择都需要配套的容量与监控。选定混合格式后,至少要监控 aof_current_size 的增长斜率、aof_last_bgrewrite_status 与磁盘剩余空间三项,缺任意一项都可能让上面的故障场景重演。
常见坑 / 最佳实践
- 备份要备份整个 appendonlydir。 只拷 base 不拷 incr 与 manifest,恢复出来的是旧快照;只拷 incr 没有 base 则根本无法加载。
- incr 过长说明重写不及时。 base 与 incr 的时间跨度太大,重放阶段拖慢恢复,检查 auto-aof-rewrite 参数是否被调小或关闭。
- 降级前先做纯 RDB 导出。 多部分 AOF 目录无法被 7.0 以下版本读取,BGSAVE 后用 dump.rdb 迁移才是安全路径。
- manifest 损坏会导致启动失败。 它是纯文本,可以人工核对与修复格式,损坏后优先对照日志里的文件清单补齐。
- 不要为了"看得见命令"关混合。 需要审计命令时用 MONITOR 或代理层日志,比牺牲恢复速度更划算。
小结
- 混合持久化 = RDB 格式的 base + AOF 增量的 incr,兼顾恢复速度与约 1 秒的丢失窗口。
- 结构与顺序由 manifest 登记,备份与恢复必须以整个 appendonlydir 为单位。
aof-use-rdb-preamble yes是默认值,改动后要触发重写才生效。- 需要文本可读性或向下兼容到 4.0 以下时才考虑关闭混合。
- 恢复耗时应当实测并记录,它是 RTO 规划的输入。
- 点赞
- 收藏
- 关注作者
评论(0)