
大家好,我是你们的老朋友。今天想和大家聊聊 Redis 的备份恢复——这个看似简单、实则坑多到能埋人的活儿。
很多人一提到 Redis 备份,张口就是“开个 BGSAVE 不就完事了?”、“RDB 文件不就是备份吗?”……说真的,我以前也这么天真过。直到某天凌晨三点,线上 Redis 集群主节点宕机,RDB 文件损坏,AOF 也没开,业务数据丢了大半,老板站在身后盯着屏幕问:“你不是说 Redis 很稳吗?”
那一刻,我才明白:在生产环境里,备份不是功能,而是责任。
先泼盆冷水:RDB 快照 ≠ 可靠备份。
Redis 默认的 RDB 快照(比如 save 900 1)只是把内存数据 dump 到磁盘,但它有几个致命问题:
我们曾经有个服务,Redis 实例 30GB,RDB 文件每天凌晨生成一次,存本地。结果某次磁盘故障,整个实例连同备份一起没了。虽然有从节点,但主从切换后发现从节点的数据也落后了 40 分钟——因为主节点在宕机前已经无法同步。
所以,真正的生产级备份,必须满足三个条件:
经过几次“事故教育”,我们现在对核心 Redis 实例采用四重保障策略:
虽然 AOF 文件比 RDB 大,恢复慢一点,但它记录的是操作日志,理论上可以做到秒级数据恢复。我们配置:
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb注意:不要用 always!性能损耗太大,everysec 是性价比最高的选择。
我们写了个脚本,每天凌晨 2 点强制执行 BGSAVE,等生成完成后,把 .rdb 和 .aof 文件打包,上传到阿里云 OSS(或 AWS S3、MinIO 等)。
关键点来了:不能直接传本地 RDB 文件!因为 Redis 运行时,RDB 文件可能正在被写入(比如 rewrite),直接 cp 可能损坏。
正确做法是:
# 先让 Redis 生成新快照
redis-cli -h $HOST -p $PORT BGSAVE
# 等待快照完成(检查 info Persistence 里的 bgsave_in_progress)
while true; do
status=$(redis-cli -h $HOST -p $PORT INFO PERSISTENCE | grep bgsave_in_progress)
if [[ "$status" == "bgsave_in_progress:0" ]]; then
break
fi
sleep 5
done
# 获取最新的 dump.rdb 路径(从 config get dir/dbfilename 拿)
DIR=$(redis-cli -h $HOST -p $PORT CONFIG GET dir | tail -1)
FILE=$(redis-cli -h $HOST -p $PORT CONFIG GET dbfilename | tail -1)
FULL_PATH="$DIR/$FILE"
# 复制到临时目录(避免后续 rewrite 覆盖)
cp "$FULL_PATH" /tmp/redis_backup_$(date +%Y%m%d).rdb
# 同样处理 AOF 文件(如果有)
if [ -f "$DIR/appendonly.aof" ]; then
cp "$DIR/appendonly.aof" /tmp/redis_aof_$(date +%Y%m%d).aof
fi
# 打包上传
tar -czf redis_backup_$(date +%Y%m%d).tar.gz /tmp/redis_backup_*.rdb /tmp/redis_aof_*.aof
ossutil cp redis_backup_*.tar.gz oss://your-bucket/redis-backups/$HOST:$PORT/这个脚本跑在独立的备份服务器上,和 Redis 实例物理隔离。
OSS 上我们用生命周期规则自动删除 7 天前的备份。同时,脚本里加了日志记录和失败告警——如果上传失败,企业微信机器人立刻@我。
最怕什么?备份了一堆,真出事发现全打不开。
所以我们每月挑一个非核心实例,从 OSS 下载备份,在测试环境完整恢复,验证数据是否一致、服务能否启动。
有一次演练就发现:AOF 文件末尾有截断,原因是 Redis 在 shutdown 时没正常关闭。后来我们在脚本里加了 redis-cli SHUTDOWN SAVE 来确保干净退出(仅用于演练环境,生产慎用)。
假设现在 Redis 主节点彻底挂了,磁盘数据全丢,怎么办?
Step 1:从对象存储下载最新备份
ossutil cp oss://your-bucket/redis-backups/10.0.0.10:6379/redis_backup_20240601.tar.gz ./
tar -xzf redis_backup_20240601.tar.gzStep 2:启动一个临时 Redis 实例指向备份文件
新建一个 redis.conf:
port 6380
dir /data/restore
dbfilename redis_backup_20240601.rdb
appendonly yes
appendfilename "redis_aof_20240601.aof"把解压出来的 RDB 和 AOF 放到 /data/restore/,然后启动:
redis-server ./redis.confRedis 会先加载 RDB,再重放 AOF 日志,最终得到接近故障前的状态。
Step 3:验证数据
用 redis-cli -p 6380 KEYS * 或业务脚本抽查关键 key,确认数据完整。
Step 4:切流量 or 数据迁移
redis-cli --cluster import 把数据导入新集群,或者用 MIGRATE 命令逐 key 迁移(适合小数据量)。⚠️ 注意:AOF 重放可能会很慢!30GB 的 AOF 文件,重放可能要 20 分钟。所以RDB + AOF 组合中,RDB 是基础,AOF 是增量补偿,尽量让 RDB 尽可能新。
FLUSHALL,从节点也会同步删除。备份必须是静态快照,不受实时操作影响。redis 用户运行脚本。有时候不需要全量恢复,只想找回某个被删的 key。这时候可以用 redis-rdb-tools 解析 RDB 文件:
rdb --command json dump.rdb > data.json
grep "user:12345" data.json或者生成 diff:
rdb -c diff yesterday.rdb > yesterday.diff
rdb -c diff today.rdb > today.diff
diff yesterday.diff today.diff这对排查“谁删了我的数据”特别有用。
Redis 很快,但快不代表不会丢数据。备份不是技术问题,是流程问题。你有没有自动化?有没有验证?有没有异地?有没有权限隔离?这些才是关键。
别等到凌晨三点才想起备份的事。花一天时间搭好备份体系,能让你未来三年睡得踏实。
如果你觉得这篇文章帮你避开了未来的坑,欢迎转发给那个总说“Redis 不用备份”的同事。也欢迎关注我的公众号,我会继续分享更多真实、带血、能落地的运维经验。
毕竟,我们不是在写代码,是在守护业务的生命线。