1. 为什么需要持久化
Redis 是内存数据库,进程退出后数据全部丢失。持久化将内存数据保存到磁盘,用于数据备份、灾难恢复和进程重启后的数据恢复。
2. RDB(Redis Database)快照
2.1 触发方式
# 手动触发
SAVE # 同步保存,阻塞主线程(生产不用)
BGSAVE # 后台异步保存,fork 子进程
# 自动触发(redis.conf)
save 900 1 # 900 秒内至少 1 个 key 变化 → 触发 BGSAVE
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化
save "" # 禁用 RDB
2.2 Copy-On-Write 原理
BGSAVE 执行时:
1. 主进程 fork() 子进程
│
├── 父进程(Redis 主线程)──→ 处理客户端请求
│ │
│ 写入 key A ──→ 页面被修改 ──→ COW 复制页面
│ │ │
│ 新数据 ──→ 新页 旧页(子进程读取)
│
└── 子进程 ──→ 读取内存页 ──→ 写入 RDB 文件
COW 开销:fork 时只需复制页表,无需复制全部内存
实际额外内存 ≈ 写入操作涉及的数据量
2.3 RDB 优缺点
| 优点 | 缺点 |
|---|---|
| 文件紧凑,备份和传输方便 | 可能丢失两次快照间的数据 |
| 恢复速度快(直接加载) | 大数据量时 fork 可能耗时较长 |
| 对运行时性能影响小 |
3. AOF(Append Only File)
3.1 写入策略
# 同步策略
appendfsync always # 每条命令 fsync → 最安全,性能最差
appendfsync everysec # 每秒 fsync → 默认,最多丢 1 秒数据
appendfsync no # 由 OS 决定 → 最快,最不安全
# 在 rewrite 期间是否不 fsync(减少 IO 压力)
no-appendfsync-on-rewrite yes
3.2 AOF 重写(Rewrite)
AOF 持续追加会不断膨胀,重写将内存中的最新数据生成精简的命令集。
BGREWRITEAOF # 手动触发重写
# 自动重写条件
auto-aof-rewrite-percentage 100 # AOF 增长超过上次重写后 100%
auto-aof-rewrite-min-size 64mb # 最小 64MB 才重写
重写流程:
1. fork 子进程,扫描内存生成新 AOF 文件
2. 父进程在此期间的新写入写入「AOF 重写缓冲区」
3. 子进程完成后,父进程将重写缓冲区的命令追加到新 AOF
4. 原子替换旧 AOF 文件
4. 混合持久化(Redis 4.0+)
aof-use-rdb-preamble yes # 默认开启
重写后的 AOF 文件格式:
┌─────────────────────────────────────────┐
│ RDB 格式头部(二进制) │ ← 全量数据快照
│ 快速加载整个数据集 │
├─────────────────────────────────────────┤
│ AOF 格式命令(文本) │ ← 重写后的增量命令
│ 保证重写期间的数据不丢失 │
└─────────────────────────────────────────┘
恢复时:
1. 读取 RDB 部分 → 快速加载全量数据
2. 执行 AOF 部分的命令 → 补齐增量数据
5. 选型与生产建议
| 场景 | 推荐 | 原因 |
|---|---|---|
| 纯缓存(可重建) | RDB + 禁用 AOF | 内存为王,重启后重建 |
| 允许分钟级丢失 | RDB only | 简单、恢复快 |
| 不能丢数据 | AOF everysec | 最多丢 1 秒 |
| 生产推荐 | RDB + AOF 混合 | 兼顾恢复速度和数据安全 |
# 生产配置示例
save 900 1
save 300 10
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 128mb
6. 持久化恢复流程
Redis 启动时的数据恢复:
1. 检查 AOF 是否开启且存在
├── AOF 存在 ──→ 加载 AOF(如果开启了混合持久化,先读 RDB 头部再读 AOF)
│ └── 校验 AOF 格式,如果损坏尝试用备份恢复
│ └── 如果备份也损坏,可以删除 AOF 直接用 RDB(会丢失部分数据)
│
└── AOF 不存在 ──→ 检查 RDB 是否存在
├── RDB 存在 ──→ 加载 RDB
│ └── RDB 加载速度快(二进制格式)
│
└── RDB 不存在 ──→ 空实例启动
恢复性能
| 数据量 | RDB 加载 | AOF 加载 (rewrite 后) |
|---|---|---|
| 1GB | 2-5s | 5-10s |
| 10GB | 20-60s | 60-120s |
| 50GB | 2-5min | 5-10min |
7. 持久化对性能的影响
| 配置 | CPU 影响 | 内存影响 | 适用场景 |
|---|---|---|---|
| AOF always | 高(每次写入都 fsync) | 低 | 金融级,不能丢数据 |
| AOF everysec(默认) | 低 | 低 | 大部分生产环境 |
| AOF no | 最低 | 低 | 可接受丢失部分数据 |
| RDB | BKSAVE 时 fork 有短暂影响 | fork 时 COW 增加 | 定时备份 |
fork 阻塞时间
# 查看最近一次 fork 耗时(微秒)
redis-cli INFO | grep latest_fork_usec
# 如果 fork 耗时较长(> 100ms),考虑:
# 1. 使用更大的 Redis 实例内存
# 2. 在 slaves 上执行 BGSAVE
# 3. 升级 Linux 内核以优化 fork 性能
8. 持久化监控指标
| 指标 | 命令 | 健康阈值 |
|---|---|---|
| RDB 最后保存时间 | INFO Persistence → rdb_last_bgsave_status | 状态为 ok |
| AOF 最后写入状态 | INFO Persistence → aof_last_bgrewrite_status | 状态为 ok |
| AOF 缓冲区大小 | INFO Persistence → aof_buffer_length | < 32MB |
| 当前 AOF 大小 | INFO Persistence → aof_current_size | 关注增长率 |
延伸阅读
总结
Redis 持久化的核心在于平衡数据安全与性能。RDB 提供紧凑的快照备份和快速恢复能力,适合灾难恢复场景;AOF 通过追加日志实现更高的数据安全性,默认每秒 fsync 的策略在多数生产环境中是最佳折中。Redis 4.0 引入的混合持久化结合了两者的优势,成为当前生产环境的首选方案。运维中需要关注 fork 操作对内存和延迟的影响,合理配置自动触发条件,并建立完善的备份与恢复流程。对于不能容忍数据丢失的核心业务,建议同时使用 RDB + AOF 混合持久化,配合主从复制实现多重数据保护。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。