Redis 7 持久化机制笔记
一、Redis 7 多部分 AOF 机制
Redis 7 将原来的单文件 appendonly.aof 拆分为三类文件:
| 文件类型 | 文件名示例 | 作用 |
|---|---|---|
| manifest 文件 | appendonly.aof.manifest |
清单文件,描述 AOF 的整体组成结构 |
| base 文件 | appendonly.aof.1.base.rdb |
基础文件,存储全量数据快照 |
| incr 文件 | appendonly.aof.1.incr.aof |
增量文件,存储 base 文件之后的写命令 |
1. base 文件的作用
base 文件是 AOF 重写(BGREWRITEAOF)时生成的数据库完整快照:
- 存储某一时刻的全量数据,作为"基线"
- 默认使用 RDB 格式,体积小、加载快
- 作为数据恢复的起点
2. 文件之间的关系
时间轴 ──────────────────────────────────────▶
T0 T1 T2 T3
│ │ │ │
▼ ▼ ▼ ▼
正常运行 触发rewrite rewrite完成 又触发rewrite
写AOF命令 fork子进程 生成base文件 生成新base文件
incr.1.aof │ base.rdb base.rdb
incr.2.aof │ (RDB+AOF格式) (RDB+AOF格式)
│ │ │ │
│ │ incr.3.aof │
│ │ │ incr.4.aof
二、数据恢复顺序与加载流程
1. 恢复优先级总览
开启 AOF? ──是──▶ 只加载 AOF 文件
│
否
▼
存在 RDB? ──是──▶ 加载 RDB 文件
│
否
▼
空数据库启动
核心原则:AOF 优先于 RDB。 同时开启时只加载 AOF,忽略 RDB。
2. Redis 7 多部分 AOF 的恢复流程
① 读取 manifest 文件 ──▶ 获取文件组成清单
② 加载 base 文件 ──▶ 恢复数据库到快照时刻的状态
③ 按顺序加载 base 之后的 incr 文件 ──▶ 回放增量写命令
④ 校验完整性,恢复完成
3. 关键点:只加载 base 之后的 incr 文件
旧的 incr 文件(base 之前)数据已归并进 base,恢复时直接跳过:
目录结构:
appendonly.aof.1.base.rdb ← 此次 rewrite 的快照
appendonly.aof.1.incr.aof ← base 之前的旧 incr(跳过)
appendonly.aof.2.incr.aof ← base 之前的旧 incr(跳过)
appendonly.aof.3.incr.aof ← base 之后的增量 ✅ 加载
appendonly.aof.4.incr.aof ← base 之后的增量 ✅ 加载
恢复顺序:base → incr.3 → incr.4
manifest 文件会明确标注哪些文件需要加载:
file seq 1 type b ← base 文件
file seq 1 type i ← base 同期的旧 incr(跳过)
file seq 2 type i ← 新的 incr(加载)
file seq 3 type i ← 新的 incr(加载)
三、为什么需要加载所有 incr 文件,而不是最后一个
核心原因:incr 文件是增量追加,不是全量覆盖
每个 incr 文件只记录特定时间段内的写命令,彼此不重叠:
base.rdb = T1 时刻的完整快照 {a:1, b:2, c:3}
incr.2.aof = T1→T2 的写命令
SET d 4, INCR a, SET e 5
incr.3.aof = T2→T3 的写命令
SET f 6, DEL b, INCR a
正确做法:base + incr.2 + incr.3
base → {a:1, b:2, c:3}
incr.2 → 执行 SET d 4, INCR a → {a:2, b:2, c:3, d:4, e:5}
incr.3 → 执行 SET f 6, DEL b → {a:3, c:3, d:4, e:5, f:6}
错误做法:只读 base + incr.3
base → {a:1, b:2, c:3}
incr.3 → 执行 SET f 6, DEL b → {a:1, c:3, f:6}
丢失了:d、e 两个 key,a 的值也不对
类比:base 是"某个时间点的账户余额",incr 文件是"之后每个月的交易流水"。只知道最后一个月的流水,无法得到正确余额------必须从头算起。
四、混合持久化模式(Hybrid Persistence)
通过 aof-use-rdb-preamble yes 开启(Redis 4.0+)。
1. 正常运行时
日常写入仍然是纯 AOF 格式,与非混合模式完全相同:
客户端写入命令 → AOF 缓冲区 → 根据 fsync 策略刷盘写入 incr 文件
2. AOF Rewrite 时(核心差异)
① 主进程 fork 子进程
② 子进程写入新的 base 文件:
┌─────────────────────────┐
│ 前半部分:RDB 格式 │ ← 全量快照,压缩率高
│ ████████████████████ │
├─────────────────────────┤
│ 后半部分:AOF 格式 │ ← fork 后的增量命令
│ SET key1 val1 │
│ INCR counter │
│ ... │
└─────────────────────────┘
③ 子进程完成,通知父进程
④ 父进程追加 rewrite 期间缓冲的增量命令
⑤ 原子替换旧文件,更新 manifest
3. 混合模式的数据恢复
① 读取 manifest,获取文件列表
② 加载 base 文件
- 识别文件头 "REDIS" 魔数 → 按 RDB 格式解析前半部分
- 遇到 RDB EOF 标记 → 切换到 AOF 格式解析后半部分
③ 按顺序加载后续 incr 文件(纯 AOF 格式,逐条回放)
④ 恢复完成
4. 四种持久化方式对比
| 对比项 | 纯 RDB | 纯 AOF | 混合模式 | 无持久化 |
|---|---|---|---|---|
| 数据安全性 | 可能丢失几分钟 | 最多丢1秒 | 最多丢1秒 | 重启全丢 |
| 文件大小 | 小 | 大 | 较小 | 无 |
| 恢复速度 | 快 | 慢 | 快 | 无需恢复 |
| 写入性能 | 不影响 | 略有开销 | 略有开销 | 最快 |
五、关键配置项速查
| 配置项 | 默认值 | 说明 |
|---|---|---|
appendonly |
no | 是否开启 AOF |
aof-use-rdb-preamble |
yes | 是否使用混合持久化 |
appendfsync |
everysec | AOF 刷盘策略 |
aof-load-truncated |
yes | AOF 截断时是否继续加载 |
rdbchecksum |
yes | RDB 是否校验 CRC64 |
auto-aof-rewrite-percentage |
100 | 触发 AOF 重写的增长比例 |
auto-aof-rewrite-min-size |
64mb | 触发 AOF 重写的最小文件大小 |
六、一句话总结
Redis 7 持久化 = base(全量快照地基) + incr(增量日志楼层)。恢复时先加载 base,再按顺序回放 base 之后的 incr 文件。混合模式下 base 前半部分用 RDB 格式加速加载,后半部分和 incr 文件用 AOF 格式保证数据安全。