2026年7月12日 · 6 分钟阅读
Redis 持久化:RDB、AOF 与混合持久化全解析
深入对比 Redis 两种持久化方式:RDB 的 COW 原理与触发时机、AOF 的写回策略与重写机制、Redis 7.0 Multi Part AOF,以及混合持久化如何兼得二者之长。
Redis 之所以被归为”缓存数据库”而不是”缓存”——就是因为它能在重启后恢复数据。这个能力来自它的持久化机制:RDB 和 AOF。
这篇文章聚焦底层原理,回答三个问题:数据是怎么写进磁盘的、什么时候写的、重启时怎么读回来。
RDB 持久化
RDB(Redis Database Backup)是全量快照,把某个时刻的所有内存数据写入磁盘。
触发方式
| 方式 | 说明 |
|---|---|
save | 同步执行,阻塞主线程,不推荐生产环境使用 |
bgsave | fork 子进程执行,不阻塞主线程,生产环境的默认选择 |
| 自动触发 | save 900 1(900 秒内至少 1 次写)等配置条件 |
| 主从复制首次同步 | slave 连接 master 时自动触发 |
| 关闭 Redis | shutdown 时自动生成 |
Copy-On-Write(写时复制)
这是 RDB 中最关键的工程原理。bgsave 执行时:
- fork:主进程 fork 出一个子进程,子进程共享主进程的内存页。
- 子进程写 RDB:子进程遍历自己的内存页,写入临时文件。
- 主进程继续服务:主进程继续处理请求。
- 读操作:直接读共享内存页,不影响子进程。
- 写操作:操作系统会将被修改的共享内存页复制一份,主进程在自己的副本上写,子进程依然引用旧页。
所以 bgsave 期间如果有大量写操作,会导致 COW 触发频繁,内存开销上升(可达到原内存的 1 倍)。这也是为什么建议单机内存不要过大(比如 8G),否则 fork 时的内存抖动可能把机器干到 OOM。
优势与劣势
优势:
- 生成的是压缩二进制文件,体积小,适合备份和灾难恢复。
- 恢复速度快——直接解析还原,不需要逐条执行命令。
劣势:
- 无法做到秒级持久化——生成快照是繁重操作,频繁执行会影响性能。
- 有数据丢失风险——两次 RDB 之间的数据若宕机则全部丢失。
- 旧版 RDB 可能不兼容新版 Redis。
AOF 持久化
AOF(Append Only File)是命令日志,每个写命令都会被追加到文件中。
工作流程
写命令 → 追加到 AOF 缓冲区 → write 写入内核缓冲区 → fsync 刷盘
整个流程分三步:
- 命令追加(Append):所有写命令追加到
server.aof_buf缓冲区。 - 文件写入(write):调用
write系统调用,将缓冲区数据写入内核缓冲区后立即返回(延迟写)。 - 文件同步(fsync):调用
fsync系统调用,强制内核缓冲区数据同步到磁盘。
fsync 策略
| 策略 | 行为 | 数据安全性 | 性能 |
|---|---|---|---|
always | 每个写命令都 fsync | 最安全,最多丢失 1 个命令 | 最慢 |
everysec | 每秒 fsync 一次 | 最多丢失 1 秒数据 | 推荐,性能较好 |
no | 由操作系统决定(Linux 默认 30s) | 最多丢失 30 秒数据 | 最快 |
生产推荐 everysec:兼顾数据安全和写入性能,最多丢一秒数据。
AOF 重写(Rewrite)
AOF 文件随着时间推移会越来越大,需要定期重写来压缩。
重写原理:不是对旧 AOF 文件进行操作,而是直接从当前数据库状态生成最小命令集。
例如,一个 key 被 SET 了 1000 次,AOF 里就记录了 1000 条 SET 命令。重写时直接读当前值,只生成一条 SET。
重写流程:
- fork 子进程,子进程基于当前内存数据生成新的 AOF 文件。
- 重写期间,新写入的命令会被记录到 AOF 重写缓冲区。
- 子进程重写完成后,把重写缓冲区的内容追加到新 AOF 文件末尾。
- 用新 AOF 文件替换旧文件。
在 Redis 7.0 之前,整个阶段的内存开销较高——所有增量数据都要在内存中保留,且写入磁盘两次。
Redis 7.0 Multi Part AOF
Redis 7.0 引入了 Multi Part AOF,彻底解决了 AOF 重写期间的资源消耗问题。
文件被分为三种类型:
| 类型 | 说明 |
|---|---|
| BASE | 基础 AOF,由重写产生,最多一个 |
| INCR | 增量 AOF,重写开始时创建,可能有多个 |
| HISTORY | 历史的 BASE 和 INCR,重写完成后自动删除 |
重写时不再攒一堆增量在内存里,而是直接写到独立的 INCR 文件。重写完成后将 BASE + INCR 合并,旧文件标记为 HISTORY 自动回收。磁盘写入次数和内存占用都大幅下降。
混合持久化(RDB + AOF)
RDB 恢复快但丢数据多,AOF 丢数据少但恢复慢(逐条执行命令)。Redis 4.0 引入了混合持久化:
- 开启方式:
aof-use-rdb-preamble yes。 - AOF 重写时,直接把当前数据以 RDB 格式 写到 AOF 文件开头,之后才是增量 AOF 命令。
[AOF 文件结构]
[RDB 部分(当前全量数据)] [AOF 部分(重写后的增量命令)]
恢复时:
- 先加载开头的 RDB 数据——极快。
- 再执行后面的增量 AOF 命令——补齐丢失的部分。
优点:兼具 RDB 的快速恢复和 AOF 的低丢数据。
缺点:AOF 文件中的 RDB 部分是二进制压缩格式,不可读。
RDB 与 AOF 对比
| 对比维度 | RDB | AOF | 混合持久化 |
|---|---|---|---|
| 文件内容 | 压缩二进制快照 | 明文写命令 | RDB + 增量 AOF |
| 文件大小 | 小 | 大 | 中等 |
| 恢复速度 | 很快 | 慢(逐条执行) | 较快 |
| 数据安全性 | 丢失较多 | everysec 最多丢 1 秒 | 同 AOF |
| 实时性 | 不可实时 | 可接近实时 | 可接近实时 |
| 可读性 | 不可读 | 可读 | 部分可读 |
| 对性能影响 | fork + COW + 磁盘 IO | 写操作 + fsync | fork + COW + fsync |
工程建议
1. 缓存场景不要开持久化
如果 Redis 只做纯缓存,丢了数据能从数据库回源,完全没必要开持久化——省掉 fork 和磁盘 IO 开销,性能和稳定性都好得多。
2. 数据重要则用混合持久化
设置 appendfsync everysec + aof-use-rdb-preamble yes。恢复时既快又稳。
3. 合理配置重写阈值
auto-aof-rewrite-percentage 100 # AOF 文件增长 100% 时触发重写
auto-aof-rewrite-min-size 64mb # AOF 文件至少 64MB 才触发重写
避免频繁重写导致磁盘 IO 飙升。
4. 大内存机器要小心 fork 耗时
单实例内存超过 8G 后,fork 时间会明显变长(可能会超过 1 秒),导致主线程停顿。建议单实例 ≤ 8G。
5. 在 slave 上做定期备份
master 只负责读写,定期在 slave 上做 bgsave,用脚本把 RDB 文件拷贝到远端。这样既不影响主节点,又能保证有灾备。
总结
- RDB 是”快照”,用 COW 做子进程写,恢复快,但丢数据多。
- AOF 是”日志”,用 write + fsync 刷盘,丢数据少,但恢复慢。
- 混合持久化把两者优势结合起来:重写时写 RDB + 增量 AOF,恢复时先加载 RDB 再回放 AOF。
- 不同的数据安全要求选择不同的持久化策略,没有银弹,只有取舍。