一、核心概念

在 Redis 故障恢复场景下,RDB 和 AOF 的主要区别体现在:

  1. 数据完整性:能恢复到哪个时间点的数据
  2. 恢复速度:从故障到服务可用的时间
  3. 恢复流程:Redis 如何选择持久化文件进行恢复
  4. 故障场景适应性:不同故障类型下的表现

二、故障恢复流程

1. Redis 启动时的恢复优先级

Redis 启动恢复流程:
┌─────────────────┐
│   Redis 启动    │
└────────┬────────┘
         │
         ▼
    检查 AOF 是否开启?
         │
    ┌────┴────┐
   是│        │否
    │         │
    ▼         ▼
AOF 存在?   RDB 存在?
    │         │
   是│        是│
    │         │
    ▼         ▼
加载 AOF   加载 RDB
    │         │
    └────┬────┘
         ▼
    恢复完成

关键规则:

  • AOF 优先级高于 RDB(如果 appendonly yes
  • 只有 AOF 不存在或损坏时,才会使用 RDB
  • 两者都不存在,Redis 以空数据启动

配置文件示例:

# 开启AOF后,优先使用AOF恢复
appendonly yes
appendfilename "appendonly.aof"

# RDB作为备份方案
save 900 1
dbfilename dump.rdb

dir /var/lib/redis

2. 不同持久化方式的恢复流程

RDB 恢复:

# 1. Redis启动,检测到 dump.rdb
# 2. 直接加载二进制数据到内存
# 3. 恢复完成,开始提供服务

redis-server /etc/redis/redis.conf
# [INFO] Loading RDB file...
# [INFO] RDB loaded in 2.5 seconds
# [INFO] Ready to accept connections

AOF 恢复:

# 1. Redis启动,检测到 appendonly.aof
# 2. 重新执行AOF文件中的每条命令
# 3. 恢复完成,开始提供服务

redis-server /etc/redis/redis.conf
# [INFO] Loading AOF file...
# [INFO] AOF loaded in 45 seconds
# [INFO] Ready to accept connections

三、故障恢复对比

1. 数据完整性(丢失数据量)

故障场景 RDB 恢复 AOF 恢复
正常关闭 丢失最后一次快照后的数据 丢失最后一次刷盘后的数据(最多1秒)
进程崩溃 丢失最后一次快照后的数据 根据刷盘策略丢失0-1秒数据
机器宕机 丢失最后一次快照后的数据 everysec:最多1秒;always:0丢失
磁盘损坏 取决于备份策略 取决于备份策略

示例场景:

场景 1:配置 save 900 1 + appendfsync everysec

时间轴:
00:00  - 上次RDB快照
00:10  - 发生大量写操作
00:15  - Redis进程崩溃

RDB恢复:丢失 00:00 - 00:15 的15分钟数据
AOF恢复:丢失 00:14:59 - 00:15:00 的1秒数据(最多)

场景 2:机器突然断电

RDB:丢失上次快照后的所有数据(可能几分钟到几小时)
AOF(always):无数据丢失(每次写都刷盘)
AOF(everysec):丢失最多1秒数据
AOF(no):丢失操作系统缓冲区数据(可能几十秒)

2. 恢复速度

实际测试数据(10GB Redis 实例):

持久化方式 文件大小 恢复时间 内存占用
RDB 2.5 GB 3 分钟 10 GB
AOF(未重写) 15 GB 60 分钟 10 GB
AOF(重写后) 3 GB 25 分钟 10 GB
混合持久化 3 GB 5 分钟 10 GB

速度差异原因:

// RDB恢复(直接加载)
void loadRDB() {
    byte[] data = readFile("dump.rdb");
    deserialize(data);  // 直接反序列化到内存
    // 时间复杂度:O(N),但常数项小
}

// AOF恢复(重新执行命令)
void loadAOF() {
    String[] commands = readFile("appendonly.aof");
    for (String cmd : commands) {
        execute(cmd);  // 逐条执行命令,涉及数据结构操作
    }
    // 时间复杂度:O(N*M),M是单条命令的时间复杂度
}

结论:

  • RDB 恢复速度 ≈ AOF 恢复速度的 5-10 倍
  • 数据量越大,RDB 优势越明显

3. 不同故障场景的适应性

场景 1:进程崩溃(OOM / Segmentation Fault)

RDB:

# 崩溃前的状态
18:00 - 最后一次BGSAVE完成
18:15 - 进程OOM崩溃

# 恢复结果
丢失 18:00 - 18:15 的15分钟数据

AOF:

# 崩溃前的状态
18:15:30.123 - 最后一次fsync成功
18:15:30.456 - 进程崩溃

# 恢复结果
丢失 18:15:30.123 - 18:15:30.456 的约0.3秒数据(everysec策略)

场景 2:AOF 文件损坏

检测与修复:

# 1. 启动时检测到AOF损坏
redis-server /etc/redis/redis.conf
# [ERROR] Bad file format reading AOF

# 2. 使用工具修复(截断损坏部分)
redis-check-aof --fix appendonly.aof
# [INFO] AOF file truncated, removed 1024 bytes

# 3. 重新启动
redis-server /etc/redis/redis.conf
# [INFO] AOF loaded successfully

RDB 作为备份:

# 如果AOF无法修复,切换到RDB恢复
mv appendonly.aof appendonly.aof.bak
redis-server /etc/redis/redis.conf
# [INFO] Loading RDB file (AOF disabled)

场景 3:误操作(FLUSHALL / FLUSHDB)

RDB:

  • ❌ 如果误操作后触发了 BGSAVE,RDB 文件会保存空数据
  • ✅ 如果有定期备份,可以恢复到备份时间点

AOF:

  • ✅ AOF 文件记录了 FLUSHALL 命令,可以手动编辑删除
  • ✅ 如果 AOF 重写还未执行,可以快速恢复

恢复步骤:

# 1. 立即停止Redis(防止AOF重写)
redis-cli SHUTDOWN NOSAVE

# 2. 编辑AOF文件,删除FLUSHALL命令
vim appendonly.aof
# 找到并删除:
# *1
# $8
# FLUSHALL

# 3. 重启Redis
redis-server /etc/redis/redis.conf

4. 恢复过程中的可用性

RDB 恢复:

  • ⏱️ 恢复时间短(分钟级)
  • ⚠️ 恢复期间完全不可用
  • ✅ 恢复完成后立即全量可用

AOF 恢复:

  • ⏱️ 恢复时间长(可能几十分钟)
  • ⚠️ 恢复期间完全不可用
  • ⚠️ 大量命令重放对系统资源消耗大

高可用方案:

主从架构 + 哨兵:
┌─────────┐
│  主节点  │ ← 宕机
└─────────┘
     │
     ├─── 从节点1 ← 哨兵提升为新主节点(秒级切换)
     │
     └─── 从节点2 ← 同步新主节点

故障转移时间:< 30 秒
无需等待持久化恢复

四、生产环境最佳实践

1. 持久化配置策略

推荐配置(混合持久化):

# 开启AOF(数据安全)
appendonly yes
appendfsync everysec

# 开启RDB(快速备份)
save 900 1
save 300 10
save 60 10000

# 开启混合持久化(Redis 4.0+)
aof-use-rdb-preamble yes

# AOF重写配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

分层策略:

┌──────────────────────────┐
│  实时数据安全:AOF      │ ← 防止进程崩溃丢数据
├──────────────────────────┤
│  快速恢复:RDB          │ ← 定期生成,备份用
├──────────────────────────┤
│  远程备份:定时RDB      │ ← 防止机器/磁盘故障
└──────────────────────────┘

2. 备份与恢复流程

定期备份脚本:

#!/bin/bash
# redis_backup.sh

REDIS_CLI="/usr/bin/redis-cli"
BACKUP_DIR="/backup/redis"
DATE=$(date +%Y%m%d_%H%M%S)

# 触发BGSAVE
$REDIS_CLI BGSAVE

# 等待BGSAVE完成
while [ $($REDIS_CLI LASTSAVE) -eq $last_save ]; do
    sleep 1
done

# 复制RDB文件
cp /var/lib/redis/dump.rdb $BACKUP_DIR/dump_$DATE.rdb

# 保留最近7天的备份
find $BACKUP_DIR -name "dump_*.rdb" -mtime +7 -delete

# 上传到远程存储(如OSS/S3)
aws s3 cp $BACKUP_DIR/dump_$DATE.rdb s3://redis-backup/

故障恢复SOP:

1. 评估故障类型
   ├─ 进程崩溃 → 自动重启(AOF恢复)
   ├─ 数据损坏 → 检查AOF → 修复/切换RDB
   └─ 误操作 → 手动编辑AOF → 重启

2. 选择恢复文件
   ├─ AOF存在且完整 → 使用AOF(数据最新)
   ├─ AOF损坏 → 尝试修复(redis-check-aof --fix)
   └─ 修复失败 → 使用最新RDB备份

3. 执行恢复
   ├─ 停止Redis
   ├─ 替换持久化文件
   ├─ 启动Redis
   └─ 验证数据完整性

4. 切换流量(如果有主从)
   ├─ 从库恢复完成
   ├─ 数据同步追赶主库
   └─ 哨兵/手动切换

3. 高可用架构下的持久化策略

主从复制 + 哨兵:

# 主节点:关闭持久化(提升性能)
appendonly no
save ""

# 从节点:开启持久化(数据安全)
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes

集群模式:

# 每个节点开启AOF
appendonly yes
appendfsync everysec

# 定期触发RDB备份(错峰执行)
# 节点1:每天凌晨1点
# 节点2:每天凌晨2点
# 节点3:每天凌晨3点

五、面试答题要点

简洁版:

Redis 故障恢复时,AOF 优先级高于 RDB。RDB 恢复快(分钟级)但可能丢失几分钟到几小时数据;AOF 恢复慢(可能几十分钟)但只丢失最多 1 秒数据(everysec 策略)。生产环境推荐开启混合持久化,结合两者优点:RDB 保证恢复速度,AOF 保证数据完整性。

详细版(回答结构):

  1. 恢复优先级
    • AOF 开启时优先用 AOF,AOF 损坏才用 RDB
  2. 数据完整性
    • RDB:可能丢失最后一次快照后的数据(分钟到小时级)
    • AOF:根据刷盘策略,最多丢失 1 秒数据
  3. 恢复速度
    • RDB:快(直接加载二进制,GB 级数据几分钟)
    • AOF:慢(重新执行命令,GB 级数据可能几十分钟)
  4. 故障场景适应性
    • 进程崩溃:AOF 数据更完整
    • 误操作:AOF 可手动修复
    • AOF 损坏:RDB 作为备份方案
  5. 生产建议
    • 开启混合持久化(Redis 4.0+)
    • 定期备份 RDB 到远程
    • 配合主从复制 + 哨兵实现高可用(秒级故障转移)