大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
RDB 与 AOF 持久化:重启之后数据怎么回来
这一课你将能做到
- 说清楚 RDB 快照与 AOF 日志各自的工作方式和取舍
- 在 Redis 7 中开启、配置并验证持久化,完成一次恢复演练
- 根据本站数据性质(排行榜可重建、验证码可丢)选择持久化策略
为什么要学
Redis 的数据在内存里,进程重启或服务器断电,内存清空。对验证码、限流计数来说,丢了无所谓;但对排行榜、用户做题进度、每日额度来说,丢一次可能引发用户投诉。
Redis 给了两条把内存数据「留住」的路:
- RDB:在某个时刻把整个数据集拍一张「照片」存进磁盘文件;
- AOF:把每一条写命令追加到日志里,重启时重放这些命令恢复数据。
还有第三条路:都不开,接受丢失。工程上没有标准答案,只有根据数据性质做的取舍,本课带你把两条路亲手跑一遍。
先建立图像
RDB(快照) AOF(日志)
某时刻: 每次写命令:
内存 {a:1,b:2,c:3} SET a 1 → 追加
│ SET b 2 → 追加
└─> dump.rdb(二进制照片) SET c 3 → 追加
重启:读照片,瞬间还原 重启:逐条重放,还原到最后一条命令
RDB:文件小、恢复快、但可能丢「拍照之后」的数据
AOF:丢得少、可读、但文件大、恢复慢
跟着做
步骤 1:查看当前持久化状态
127.0.0.1:6379> CONFIG GET save
1) "save"
2) "3600 1 300 100 60 10000"
127.0.0.1:6379> CONFIG GET appendonly
1) "appendonly"
2) "no"
默认配置:AOF 关闭;RDB 按规则自动触发(3600 秒内 1 次写、300 秒内 100 次写、60 秒内 10000 次写,满足任一就拍快照)。
步骤 2:手动触发 RDB
写入一些数据:
127.0.0.1:6379> ZADD rank:course:7:weekly 980 user:1003 870 user:1001
(integer) 2
BGSAVE 让 Redis fork 出子进程在后台拍照(不阻塞服务):
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> LASTSAVE
(integer) 1760000100
LASTSAVE 返回最近一次成功快照的时间戳。另有 SAVE 命令在前台执行(阻塞所有请求),只在维护窗口使用。
查看容器里生成的文件:
docker exec redis7 ls -l /data
能看到 dump.rdb。
步骤 3:用 RDB 做一次恢复演练
先继续写一条「拍照之后」的新数据:
127.0.0.1:6379> ZADD rank:course:7:weekly 720 user:1002
(integer) 1
强制删除容器(模拟宕机且未及快照):
docker rm -f redis7
重新启动一个挂载了同一数据目录的容器(Docker 环境下注意把 /data 挂载到宿主机卷,之前 docker run 可加 -v redisdata:/data):
docker run -d --name redis7 -v redisdata:/data -p 6379:6379 redis:7
连进去查看:
127.0.0.1:6379> ZRANGE rank:course:7:weekly 0 -1 WITHSCORES
你会看到快照时刻的数据,而「拍照之后」写入的 user:1002 不在——这就是 RDB 的丢失窗口,亲眼见过一次胜过背诵。
步骤 4:开启 AOF
127.0.0.1:6379> CONFIG SET appendonly yes
OK
127.0.0.1:6379> CONFIG SET appendfsync everysec
OK
Redis 会立刻做一次内存数据的初始重写生成 AOF。Redis 7 的 AOF 有重要变化:采用多部分 AOF,文件放在 appenddirname 指定的目录(默认 appendonlydir)里,由基础文件、增量文件和清单组成,比老版本单文件更健壮:
docker exec redis7 ls -l /data/appendonlydir
步骤 5:理解三种刷盘策略
appendfsync always 每条写命令都刷磁盘:最安全,性能最低
appendfsync everysec 每秒刷一次:兼顾,宕机最多丢 1 秒数据(默认推荐)
appendfsync no 交给操作系统决定:最快,丢失不可控
本站选择 everysec:判题积分在极端宕机时最多丢 1 秒,完全可接受。
步骤 6:AOF 重写,控制文件体积
AOF 不断追加会越来越大(同一计数器被加了一万次,日志里就有一万条 INCR)。BGREWRITEAOF 用最少的命令重建一份等价日志:
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started
也可配置自动触发阈值(auto-aof-rewrite-percentage、auto-aof-rewrite-min-size)。重写期间新的写命令照常处理,子进程负责生成新文件。
步骤 7:用 AOF 恢复并处理损坏
重启 Redis(AOF 已开启):
127.0.0.1:6379> SHUTDOWN
not connected> exit
重新启动容器后连接,数据回到了停机前一刻,且只可能少最后约 1 秒。
如果 AOF 文件因磁盘故障损坏,Redis 默认会拒绝启动(宁可不起也不加载半截数据)。修复工具:
docker exec redis7 redis-check-aof --fix /data/appendonlydir/对应的增量.aof
它会截掉文件尾部不完整的命令,修复后再启动。RDB 对应工具是 redis-check-rdb。
讲清楚要点
- RDB 是紧凑的时间点快照:文件小、恢复快、适合备份与灾备传走;缺点是两次快照之间的数据会丢。
- AOF 是命令日志:everysec 下最多丢 1 秒;可读性好(能看到命令);缺点是文件大、恢复慢,需要重写治理。
- 可以同时开启:Redis 重启时优先使用 AOF(数据更完整),RDB 仍可作为冷备。本站排行榜场景推荐「AOF everysec + 保留 RDB 备份」。
- Redis 7 的 AOF 是多部分结构:不再是单个 appendonly.aof,运维脚本和备份路径要更新到 appendonlydir 目录。
- fork 是持久化的底层机制:BGSAVE/AOF 重写都靠子进程;实例很大时 fork 本身有开销(Copy-On-Write),需要监控
latest_fork_usec。 - 纯缓存场景可以全关:数据允许丢失且能重建时,关闭持久化反而性能更好、启动更快。
你可能会懵的地方
-
快照期间还在写数据,照片拍的是哪个时刻? fork 出子进程的那一刻。操作系统用写时复制保证子进程看到的是那一刻的内存,之后父进程的新写入不影响照片。
-
同时开了 RDB 和 AOF,重启听谁的? 只听 AOF,因为 AOF 数据通常更完整。RDB 不参与启动恢复,只用于备份。
-
AOF 重写会不会把正在处理的写命令漏掉? 不会。重写开始后,新写命令除了写旧 AOF,还会被记入重写缓冲,子进程完成后把缓冲区命令补上,再原子切换文件。
-
持久化开了是不是就等于高可用? 不是。持久化只解决「重启后数据回来」,机器整体故障仍然中断服务。高可用要靠主从复制和哨兵/集群(第 11 课)。
-
每天备份一次,备份放本机够吗? 不够。机器损坏备份一起没。RDB/AOF 备份应定期传到异地或对象存储,并定期做恢复演练——备份不能恢复等于没备份。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 生产只靠默认 RDB,以为不丢数据 | 快照间隔内数据全丢 | 重要数据开 AOF everysec |
| AOF 用 always 追极致安全 | 每条命令刷盘,性能暴跌 | everysec 已足够 |
| AOF 长期不重写 | 文件巨大,恢复极慢 | 配置自动重写阈值 |
| 备份只放服务器本地 | 机器故障备份俱毁 | 异地备份 + 定期恢复演练 |
| 运维还在找 appendonly.aof 单文件 | Redis 7 已改多部分目录 | 操作 appendonlydir |
| 大实例白天手动 SAVE | 前台阻塞全站 | 一律 BGSAVE / BGREWRITEAOF |
卡点急救
- 重启后数据没回来:检查 appendonly 是否为 yes、数据目录是否正确挂载;AOF 损坏时看启动日志并用 redis-check-aof 修复。
- BGSAVE 失败:
INFO persistence看报错,常见是磁盘满或内存不足导致 fork 失败;清理空间并监控rdb_last_bgsave_status。 - AOF 文件暴增:先手动 BGREWRITEAOF 救急,再检查自动重写配置是否被改小或关闭。
面试常问
-
RDB 和 AOF 的区别?怎么选? RDB 是时间点快照,紧凑、恢复快,但会丢快照间隔数据,适合备份;AOF 记录写命令,everysec 下最多丢 1 秒,更安全但文件大、恢复慢。重要数据可 AOF + RDB 并用,重启优先 AOF;纯缓存可全关。
-
AOF 重写的作用和过程? 用最少命令生成等价日志以控制体积;子进程基于当前数据生成,期间新命令进重写缓冲,完成后追加并原子替换。
-
Redis 7 的 AOF 有什么变化? 由单文件改为 appendonlydir 下的多部分文件(基础、增量、清单),重写与加载更健壮。
自测三问
- 写出「AOF 每秒刷盘」的配置命令,并说出宕机最多丢多久的数据。
- RDB 恢复快但为什么可能丢数据?丢失窗口从哪到哪?
- 同时开启两种持久化时,重启以哪个为准?另一个还有什么价值?
小结一句话
RDB 拍照小而快、AOF 记账全而稳,本站的正确姿势是「AOF everysec 兜底 + RDB 异地备份 + 定期恢复演练」。
延伸
- 持久化文档
- Redis 7 AOF 说明
- 下一课:集群、安全与运维——从单机走向生产。