从备份恢复 Redis 实例:完整演练步骤
备份的价值只有一次机会验证——真的要恢复的时候。与其赌那天一切顺利,不如定期在隔离环境把恢复流程完整跑一遍。本文给出一套可直接照做的 runbook,覆盖备份校验、加载、验证与切流收尾。
一、准备:确认备份资产与版本
恢复前先盘点三件事:
- 备份形态:纯 RDB 文件,还是 appendonlydir 整目录(base + incr + manifest)。AOF 开启的实例必须备目录,只备 dump.rdb 恢复出来的是旧快照。
- 版本兼容:目标 redis-server 版本必须不低于备份生成版本,高版本能加载低版本的 RDB,反之不行(Redis 7.0 的 RDB 版本号为 10、7.2 为 11,含 listpack 等新编码)。
- 校验记录:每个备份都应附带 md5 与 redis-check-rdb 的体检结果,缺失就现场补一次。
md5sum -c /backup/rdb-20261024.md5
redis-check-rdb /backup/rdb-20261024/dump.rdb
redis-check-aof /backup/appendonlydir/appendonly.aof.manifest
redis-check-aof 接 manifest 文件会依次检查全部部件;尾部截断时它会给出用 --fix 截去损坏尾部的选项——先分析再决定,不要上来就 fix。
版本兼容的判断依据不止 redis-server 的版本号,还要看 RDB 文件里记录的版本。RDB 格式版本与 Redis 版本并非一一对应:Redis 6.2 写出的 RDB 版本是 9,7.0 是 10,7.2 是 11。用 redis-check-rdb 的输出可以直接读出 RDB version,拿这个值与目标实例支持的上限比较,比看发行版本号更准确。跨大版本恢复时还要注意编码差异:7.0 开始 listpack 取代 ziplist,若备份里含 listpack 编码的集合而目标版本不支持,加载会直接报 Unknown encoding type。
另外要确认 dir 参数。恢复时最容易出的一类错误是把文件放到了正确目录、但配置文件里的 dir 指向了别处,结果实例起来是个空库。第 3 步的 grep 就是为此准备的,必须逐项核对 dir、appenddirname、dbfilename 三个路径相关配置,而不是只看 appendonly。
二、恢复 AOF 实例的完整步骤
以开启混合持久化的实例为例:
# 1. 停实例(或在新机器操作)
systemctl stop redis
# 2. 放回备份
rsync -a /backup/appendonlydir/ /var/lib/redis/appendonlydir/
chown -R redis:redis /var/lib/redis
# 3. 核对配置与备份时一致
grep -E "^(appendonly|appenddirname|dir|aof-use-rdb-preamble)" /etc/redis/redis.conf
# 4. 以隔离端口启动,避免直接对外
redis-server /etc/redis/redis.conf --port 6380
# 5. 观察加载
tail -f /var/log/redis/redis-server.log
# Reading RDB base file on AOF loading
# DB loaded from append only file: 38.517 seconds
加载期间 redis-cli 返回 -LOADING 错误属正常;日志中两条记录分别对应 base 的 RDB 解析与整体完成时间,后者就是这套备份的实测恢复耗时。
redis-cli -p 6380 DBSIZE 这类命令在加载期间会被拒绝,返回 LOADING Redis is loading the dataset in memory,这是预期行为而不是故障。判断加载是否结束的可靠方式是查日志,或者轮询 INFO persistence 里的 loading:0:
redis-cli -p 6380 INFO persistence | grep -E "^loading|rdb_last_load_keys"
# loading:0
# rdb_last_load_keys_loaded:5382104
# rdb_last_load_keys_expired:3712
rdb_last_load_keys_loaded 记录本次加载的 key 数量,rdb_last_load_keys_expired 是加载过程中因过期被丢弃的数量(这两个字段自 7.0 起提供)。后者不为零是正常的——快照是在某个时刻拍的,加载时已经过了 TTL,这部分键本就不该存在。对账时应当用"加载数减去过期数"与备份前记录的 DBSIZE 比较,而不是拿原始加载数硬比,否则每次都会差出几千个键,误判为数据丢失。
三、验证清单
逐项核对,任何一项不过关都不进入切流:
- 数量对账:DBSIZE 与备份前记录比对,误差在过期键的合理范围内;
- 抽样验证:按业务挑 10~20 个关键 key,核对类型、值与 TTL;
- 键空间分布:INFO keyspace 确认各 DB 的键数与预期一致;
- 内存水位:INFO memory 的 used_memory 与备份前同量级,异常偏大常见于重放后的碎片累积;
- 复制验证:临时挂一个从库完成全量同步,确认新实例能作为正常主库工作。
五项里前三项验证"数据在不在",后两项验证"实例健不健康"。复制验证常被省略,但它是唯一能证明"新实例有正常主库行为"的动作——replid 是否已生成、master_repl_offset 是否在推进、从库能否完成全量,只有真挂一个从库才能看出来。演练环境的从库可以是同机另一个端口,不需要真实资源投入。
redis-cli -p 6380 DBSIZE
redis-cli -p 6380 INFO keyspace
redis-cli -p 6380 --no-raw GET business:config:version
四、切流与收尾
- 切流:应用配置指向新实例(或恢复原端口),优先灰度部分应用实例观察命中率与错误率,再全量放开;
- 生成新基线:切流后立即 BGSAVE,此后备份链基于新实例重建;
- 数据补录评估:从最后一次备份到故障时刻之间的数据缺口,配合业务日志或上游消息评估是否需要补录;
- 复盘归档:记录实际 RTO/RPO 与预估的差距,更新 runbook 与备份巡检规则。
五、把演练变成例行
建议每季度跑一次完整演练,环境隔离、可直接使用真实备份。考核三个数字:备份到可用的加载耗时、从发现故障到恢复的总时长、验证环节拦截问题的次数。数字劣化往往先于故障出现——磁盘变慢、文件变大、流程走样,都会体现在这组指标里。
三个数字里"从发现故障到恢复的总时长"最容易被低估,因为它包含大量与 Redis 无关的环节。一次真实恢复的时间构成大致是:确认故障与决策 5~15 分钟、定位可用备份 5 分钟、拷贝备份(取决于体积与带宽)、加载(数秒到数分钟)、验证清单(10~20 分钟)、切流与观察(10 分钟以上)。多数团队只在演练中测了"加载耗时"这一段,把这个数字报成 RTO,实际能力被高估一个量级。演练时应当从"假定告警响起"开始计时,把人的反应时间和跨团队沟通都算进去,得到的才是能对外承诺的数字。
常见坑 / 最佳实践
- 恢复前不校验备份。 md5 与 redis-check-rdb 是十分钟的事,能避免"流程走到加载才发现备份是坏的"。
- 恢复与升级混做。 恢复环境顺手装最新版,配置项与文件格式双重意外;两个动作必须分开做、分开验证。
- 跳过隔离端口直接对外。 加载慢、数据错都会直接影响业务,6380 这类隔离端口是低成本的安全垫。
- 把 --fix 当第一反应。 截断意味着丢数据,先让 redis-check-aof 分析损坏范围,评估可接受再动手。
- 恢复后不做对账。 DBSIZE 对不上、TTL 丢失未被发现,业务侧的诡异问题会追溯半天,验证清单逐项过是最快的路。
小结
- 备份资产以形态为准:AOF 实例必须整目录备份,附带 md5 与体检记录。
- 版本兼容原则是"恢复端不低于生成端",恢复与升级不要混在一次操作里。
- 标准流程:校验、放回、隔离端口启动、观察加载日志、验证清单、切流、新基线、复盘。
- 加载日志的耗时就是实测 RTO 的核心数据,验证清单拦截的是"恢复成功但数据不对"的隐形故障。
- 季度演练常态化,用三项指标衡量恢复能力的退化趋势。
- 点赞
- 收藏
- 关注作者
评论(0)