Redis RDB 持久化详解
RDB(Redis Database Backup)是 Redis 的快照式持久化机制,通过定期保存数据快照实现数据持久化。本文将深入 RDB 的原理、配置和优化。
一、RDB 基础概念
1.1 什么是 RDB
RDB 是时间点快照:
- 定期保存数据快照
- 二进制格式,紧凑
- 适合备份和恢复
数据状态 RDB 文件
┌─────────┐ ┌─────────────┐
│ Key-Value│ 快照 │ dump.rdb │
│ Memory │ ──────▶ │ (二进制) │
└─────────┘ └─────────────┘
1.2 RDB 文件结构
RDB 文件格式:
┌─────────────────┐
│ REDIS0009 │ ← 魔数 + 版本
├─────────────────┤
│ 数据库选择 │
├─────────────────┤
│ 键值对 1 │
├─────────────────┤
│ 键值对 2 │
├─────────────────┤
│ ... │
├─────────────────┤
│ EOF │ ← 结束标记
├─────────────────┤
│ CRC64 校验和 │ ← 完整性校验
└─────────────────┘
二、触发方式
2.1 自动触发
配置触发条件:
# redis.conf
save 900 1 # 900 秒内至少 1 个键变化
save 300 10 # 300 秒内至少 10 个键变化
save 60 10000 # 60 秒内至少 10000 个键变化
触发流程:
满足 save 条件
↓
BGSAVE 命令
↓
fork 子进程
↓
子进程写 RDB 文件
↓
父进程继续服务
2.2 手动触发
# 阻塞保存(不推荐生产)
SAVE
# 后台保存(推荐)
BGSAVE
# 检查保存状态
LASTSAVE
# 停止 BGSAVE
BGSAVE ABORT
2.3 关闭 RDB
# 禁用 RDB
save ""
# 或注释所有 save 配置
# save 900 1
# save 300 10
# save 60 10000
三、工作原理
3.1 fork 子进程
// BGSAVE 实现
void bgsaveCommand(client *c) {
// 1. 检查是否已有 BGSAVE 在运行
if (server.child_type == CHILD_TYPE_RDB) {
addReplyError(c, "BGSAVE already in progress");
return;
}
// 2. fork 子进程
pid_t childpid = fork();
if (childpid == 0) {
// 子进程:执行 RDB 保存
rdbSaveBackground();
} else {
// 父进程:继续服务
server.rdb_child_pid = childpid;
}
}
3.2 写时复制(Copy-on-Write)
fork 后:
父进程 子进程
│ │
│ 继续处理写请求 │
│ │
│ 写页 P │
│ │
├─ 触发 COW │
│ 复制页 P │
│ │
│ 写入新页 P' │ 读取旧页 P(快照)
│ │
优势:
- 父进程不阻塞
- 只复制修改的页
- 内存开销小
3.3 保存流程
1. 创建临时文件 temp-7832.rdb
2. 遍历所有数据库
3. 序列化键值对
4. 写入临时文件
5. 重命名为 dump.rdb
6. 通知父进程完成
四、配置详解
4.1 基本配置
# RDB 文件名
dbfilename dump.rdb
# 工作目录
dir /var/lib/redis
# 压缩
rdbcompression yes
# 校验和
rdbchecksum yes
4.2 触发条件
# 保存条件(满足任一即触发)
save 900 1 # 15 分钟内至少 1 个键变化
save 300 10 # 5 分钟内至少 10 个键变化
save 60 10000 # 1 分钟内至少 1 万个键变化
# 建议配置(根据业务调整)
save 300 100 # 5 分钟 100 个变化
save 60 1000 # 1 分钟 1000 个变化
4.3 停止保存
# 写入失败时继续服务
stop-writes-on-bgsave-error no
# 默认配置(推荐)
stop-writes-on-bgsave-error yes
五、数据恢复
5.1 启动恢复
Redis 启动
↓
检查 dump.rdb 存在
↓
加载 RDB 文件
↓
恢复数据到内存
↓
启动完成
5.2 手动恢复
# 1. 停止 Redis
redis-cli SHUTDOWN
# 2. 备份当前 RDB
cp /var/lib/redis/dump.rdb /var/lib/redis/dump.rdb.bak
# 3. 替换 RDB 文件
cp backup/dump.rdb /var/lib/redis/
# 4. 启动 Redis
redis-server /etc/redis/redis.conf
5.3 恢复验证
# 检查 RDB 文件
redis-check-rdb /var/lib/redis/dump.rdb
# 输出示例
[offset 0] Checking RDB file /var/lib/redis/dump.rdb
[offset 10] AUX FIELD 'redis-ver' = '7.0.0'
[offset 20] AUX FIELD 'aof-preamble' = '0'
...
RDB file is OK
六、性能优化
6.1 fork 优化
问题:
fork 时可能阻塞
大数据集 fork 耗时
解决:
# 控制最大内存
maxmemory 4gb
# 避免大 Key
# 单个 Key < 10KB
6.2 磁盘优化
# 使用 SSD
dir /mnt/ssd/redis
# 禁用透明大页
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 调整 swappiness
sysctl vm.swappiness=1
6.3 配置建议
# 生产环境推荐
save 300 100
save 60 1000
rdbcompression yes
rdbchecksum yes
stop-writes-on-bgsave-error yes
dir /var/lib/redis
dbfilename dump.rdb
七、监控与维护
7.1 监控指标
# 查看 RDB 状态
INFO persistence
# 输出示例
# Persistence
# loading:0
# current_cow_size:0
# last_save_time:1640000000
# last_bgsave_status:ok
# rdb_changes_since_last_save:100
7.2 定期备份
#!/bin/bash
# backup.sh
REDIS_CLI="redis-cli"
BACKUP_DIR="/backup/redis"
DATE=$(date +%Y%m%d_%H%M%S)
# 触发 BGSAVE
$REDIS_CLI BGSAVE
# 等待完成
while [ "$($REDIS_CLI LASTSAVE)" == "$LAST_SAVE" ]; do
sleep 1
done
# 备份 RDB 文件
cp /var/lib/redis/dump.rdb $BACKUP_DIR/dump_$DATE.rdb
# 压缩
gzip $BACKUP_DIR/dump_$DATE.rdb
# 清理 7 天前备份
find $BACKUP_DIR -name "dump_*.rdb.gz" -mtime +7 -delete
7.3 故障处理
问题 1: BGSAVE 失败
# 检查磁盘空间
df -h
# 检查权限
ls -la /var/lib/redis/
# 查看日志
tail -f /var/log/redis/redis.log
问题 2: RDB 文件损坏
# 检查文件
redis-check-rdb /var/lib/redis/dump.rdb
# 从备份恢复
cp /backup/redis/dump_20240101.rdb /var/lib/redis/dump.rdb
八、最佳实践
8.1 配置策略
| 场景 | 配置 |
|---|---|
| 高可用 | save 60 1000 + AOF |
| 缓存 | 禁用 RDB |
| 备份 | save 300 100 + 定期备份 |
| 开发 | save 60 1 |
8.2 备份策略
每小时:本地备份
每天:异地备份
每周:归档备份
8.3 恢复演练
每月进行一次恢复演练:
1. 从备份恢复
2. 验证数据完整性
3. 记录恢复时间
4. 优化恢复流程
九、常见问题
Q1: RDB vs AOF?
RDB:
- 紧凑,适合备份
- 恢复快
- 可能丢失数据
AOF:
- 数据更安全
- 文件较大
- 恢复慢
建议:同时开启
Q2: fork 失败怎么办?
# 检查内存
free -h
# 检查系统配置
cat /proc/sys/vm/overcommit_memory
# 设置为 1(允许过度分配)
echo 1 > /proc/sys/vm/overcommit_memory
Q3: RDB 文件过大?
# 1. 检查大 Key
redis-cli --bigkeys
# 2. 启用压缩
rdbcompression yes
# 3. 定期清理过期数据
Q4: 如何迁移 RDB 文件?
# 1. 源服务器
BGSAVE
# 2. 复制文件
scp /var/lib/redis/dump.rdb target:/var/lib/redis/
# 3. 目标服务器
redis-cli SHUTDOWN
mv /var/lib/redis/dump.rdb /var/lib/redis/dump.rdb.bak
mv /var/lib/redis/dump.rdb.new /var/lib/redis/dump.rdb
redis-server
总结
Redis RDB 核心要点:
| 特性 | 说明 |
|---|---|
| 格式 | 二进制快照 |
| 触发 | save 配置、BGSAVE |
| 优势 | 紧凑、恢复快 |
| 劣势 | 可能丢失数据 |
| 适用 | 备份、冷恢复 |
最佳实践:
- 合理配置 save 条件
- 启用压缩和校验
- 定期备份到异地
- 监控 BGSAVE 状态
- 定期恢复演练
掌握 RDB,保障 Redis 数据安全!