RDB vs AOF 对比与混合持久化
面试官:「Redis 持久化用 RDB 还是 AOF?」
你:「都用。」
面试官眉毛一挑:「说说看。」
好,这篇文章帮你把这个问题的答案讲透。
RDB vs AOF 全方位对比
核心原理对比
| 维度 | RDB | AOF |
|---|---|---|
| 持久化方式 | 二进制快照 | 追加写命令 |
| 文件格式 | 二进制压缩格式 | 文本命令 |
| 数据完整性 | 快照时刻的数据 | 可以更实时 |
| 恢复速度 | 快(直接加载) | 慢(重放命令) |
| 文件大小 | 小 | 大 |
| 对性能影响 | fork 子进程,短暂阻塞 | 持续 I/O 开销 |
数据安全性对比
假设每分钟写操作数相同:
| 场景 | RDB | AOF |
|---|---|---|
| 每 5 分钟快照 | 最多丢失 5 分钟数据 | - |
| AOF everysec | - | 最多丢失 1 秒数据 |
| AOF always | - | 数据完全不丢失 |
结论:AOF 的数据安全性更高。
性能对比
┌─────────────────────────────────────────────────────────────────┐
│ 写操作性能 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ RDB: │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 处理 │────▶│ fork │────▶│ 快照 │────▶│ 返回 │ │
│ │ 写入 │ │ 子进程 │ │ 写入 │ │ │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ ↓ ↓ │
│ 正常速度 fork 期间短暂阻塞(毫秒~秒级) │
│ │
│ AOF: │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 处理 │────▶│ 写入 │────▶│ 刷盘 │────▶ 返回 │
│ │ 写入 │ │ 缓冲区 │ │ (根据策略) │ │
│ └──────┘ └──────┘ └──────┘ │
│ ↓ ↓ │
│ 正常速度 缓冲区写入 everysec 模式每秒一次 │
│ 同步到磁盘 │
│ │
└─────────────────────────────────────────────────────────────────┘资源占用对比
| 资源 | RDB | AOF |
|---|---|---|
| CPU | fork + 压缩时较高 | 持续写入,略有影响 |
| 内存 | COW 期间可能翻倍 | 正常 |
| 磁盘 I/O | 快照时集中写入 | 持续追加写入 |
| 文件大小 | 紧凑(压缩) | 膨胀(追加命令) |
各自优缺点总结
RDB
| 优点 | 缺点 |
|---|---|
| 文件紧凑,恢复快 | 可能丢失快照间隔的数据 |
| 对性能影响小 | fork 可能耗时(大数据量时) |
| 适合备份和灾难恢复 | - |
| 适合冷备份 | - |
AOF
| 优点 | 缺点 |
|---|---|
| 数据安全性高 | 文件较大 |
| 可配置刷盘策略 | 恢复速度慢 |
| 日志格式可读 | 极端情况下可能比 RDB 慢 |
| 支持重写压缩 | - |
混合持久化:鱼和熊掌兼得
什么是混合持久化?
Redis 4.0 引入了 混合持久化,结合 RDB 和 AOF 的优点:
┌─────────────────────────────────────────────────────────────────┐
│ 混合 AOF 文件 │
│ │
│ [RDB 二进制格式] │ [AOF 文本格式] │
│ (数据快照,快) │ (增量命令,紧凑) │
│ │
└─────────────────────────────────────────────────────────────────┘为什么混合持久化更好?
| 场景 | 纯 AOF | 混合持久化 |
|---|---|---|
| 恢复速度 | 慢(重放所有命令) | 快(RDB 部分直接加载) |
| 文件大小 | 大(全量 AOF 命令) | 小(RDB 二进制紧凑) |
| 数据安全 | 高(可配置) | 高(结合两者) |
配置混合持久化
bash
# redis.conf
# 开启 AOF
appendonly yes
# 开启混合持久化(Redis 4.0+)
aof-use-rdb-preamble yes
# AOF 写入策略
appendfsync everysec混合持久化的工作流程
┌─────────────────────────────────────────────────────────────────┐
│ 正常运行时 │
│ │
│ 写操作 → AOF 缓冲区 → 刷盘(everysec) │
│ │
└─────────────────────────────────────────────────────────────────┘
│
│ 触发 AOF 重写
▼
┌─────────────────────────────────────────────────────────────────┐
│ AOF 重写时 │
│ │
│ fork 子进程 │
│ │ │
│ ├─→ 生成 RDB 格式的完整数据快照 │
│ │ │
│ └─→ 生成后续的 AOF 增量命令 │
│ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 重写后的文件 │
│ │
│ [RDB 快照] + [AOF 增量] │
│ │
└─────────────────────────────────────────────────────────────────┘恢复时的加载顺序
Redis 7.0 之前的版本:
1. 检查 AOF 是否存在
2. 如果有 AOF,优先加载 AOF
- 混合 AOF:先解析 RDB 部分,再追加 AOF 部分
- 纯 AOF:重放所有命令
3. 如果没有 AOF,加载 RDBRedis 7.0+(Multi-Part AOF):
1. 读取 manifest 文件
2. 按顺序加载 base 文件(RDB 格式)
3. 依次加载 incr 文件(AOF 格式)
4. 合并恢复数据最佳实践:如何选择?
场景一:追求极致性能,允许分钟级数据丢失
bash
# 只用 RDB
save 900 1
save 300 10
save 60 10000
appendonly no场景二:需要高性能又要数据安全
bash
# RDB + AOF 混合(推荐)
save 3600 1
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes场景三:金融级数据安全
bash
# 只用 AOF + always
appendonly yes
appendfsync always
# 可以关闭 RDB 自动快照
save ""场景四:数据量大,恢复要快
bash
# 混合持久化 + 合理的重写配置
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 1gb生产环境配置模板
bash
# redis.conf - 持久化配置
# ==================== RDB ====================
# 自动快照
save 900 1
save 300 10
save 60 10000
# RDB 文件
dbfilename dump.rdb
dir /var/lib/redis
# RDB 压缩
rdbcompression yes
rdbchecksum yes
# ==================== AOF ====================
# 开启 AOF
appendonly yes
appendfilename "appendonly.aof"
# 写入策略
appendfsync everysec
# AOF 重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 混合持久化
aof-use-rdb-preamble yes
# 异常处理
aof-load-truncated yes
aof-rewrite-incremental-fsync yes监控和运维
关键监控指标
bash
redis-cli INFO persistence# RDB 相关
rdb_changes_since_last_save:0 # 距离上次快照的变更次数
rdb_last_save_time:1700000000 # 上次快照时间
rdb_last_bgsave_status:ok # 上次 bgsave 状态
rdb_last_bgsave_time_sec:1 # 上次 bgsave 耗时(秒)
rdb_current_bgsave_time_sec:-1 # 当前 bgsave 耗时
# AOF 相关
aof_enabled:1 # AOF 是否开启
aof_current_size:1073741824 # 当前 AOF 大小
aof_base_size:536870912 # 上次重写时大小
aof_pending_rewrite:0 # 是否有重写任务
aof_last_write_status:ok # 上次写入状态
aof_last_write_buf_sizes:0,0 # 缓冲区大小定时任务示例
bash
#!/bin/bash
# backup-redis.sh
DATE=$(date +%Y%m%d%H%M%S)
# 备份 RDB
cp /var/lib/redis/dump.rdb /backup/redis/dump-$DATE.rdb
# 备份 AOF
cp /var/lib/redis/appendonly.aof /backup/redis/appendonly-$DATE.aof
# 清理 7 天前的备份
find /backup/redis -name "*.rdb" -mtime +7 -delete
find /backup/redis -name "*.aof" -mtime +7 -delete面试题讲解
面试题:RDB 和 AOF 哪个更好?
普通回答: 「RDB 恢复快,AOF 数据安全。」
面试官想听: 「这要看场景。对于大多数业务,推荐混合持久化,既有 RDB 的快速恢复,又有 AOF 的数据安全。具体来说……」
面试题:Redis 持久化会阻塞吗?
普通回答: 「RDB 会阻塞。」
面试官想听: 「不完全是。SAVE 会阻塞,但 BGSAVE 是 fork 子进程处理,不阻塞主进程。唯一可能阻塞的情况是……」
面试题:同时开启 RDB 和 AOF,Redis 会加载哪个?
普通回答: 「AOF。」
面试官想听: 「Redis 优先加载 AOF。如果 AOF 开启,会优先用 AOF 恢复数据……」
总结
| 特性 | RDB | AOF | 混合持久化 |
|---|---|---|---|
| 持久化方式 | 快照 | 命令追加 | RDB + AOF |
| 数据完整性 | 较低 | 高 | 高 |
| 恢复速度 | 快 | 慢 | 快 |
| 文件大小 | 小 | 大 | 中等 |
| 性能影响 | fork 时短暂阻塞 | 持续 I/O | 适中 |
| 推荐程度 | 一般 | 推荐 | 强烈推荐 |
留给你的问题
假设你的 Redis 开启了混合持久化,某天磁盘损坏了,只有内存数据还在。
这种情况下,应该用 RDB 恢复还是 AOF 恢复?哪个能恢复更多数据?
提示:考虑两种持久化的数据时效性。
