Redis BGSAVE 与 SAVE 的区别
概述
BGSAVE 和 SAVE 是 Redis 创建 RDB 快照的两种方式。虽然它们的目的相同——生成一个包含全量数据的 RDB 文件,但它们的执行方式和影响截然不同。
核心区别速览
| 特性 | SAVE | BGSAVE |
|---|---|---|
| 执行方式 | 同步(阻塞) | 异步(后台) |
| 对服务的影响 | 完全阻塞 | 几乎无影响 |
| 使用场景 | 停机维护/关机前 | 生产环境常规备份 |
| 返回值 | OK | “Background saving started” |
| 子进程 | 无(主进程直接做) | fork 子进程执行 |
| 内存消耗 | 不额外消耗 | COW 可能增加内存 |
| 耗时 | 写 RDB 时长 | fork 时长 + 写 RDB 时长 |
工作原理对比
SAVE 的工作流程
客户端发送 SAVE 命令
↓
Redis 主进程接收命令
↓
主进程开始写入 RDB 文件
↓── 在此期间 Redis 完全阻塞
│ - 不处理任何客户端请求
│ - 不执行定时任务
│ - 不响应心跳
↓
写入完成
↓
主进程恢复处理请求
↓
返回 OK
BGSAVE 的工作流程
客户端发送 BGSAVE 命令
↓
Redis 主进程 fork() 出子进程
↓── fork 期间短暂阻塞(毫秒级到几秒)
│ - 复制页表
│ - COW 机制准备
↓
子进程负责写入 RDB 文件
↓── 主进程立即恢复处理请求
│ - 正常处理所有客户端命令
│ - 通过 COW 机制共享内存
│ - 修改数据时复制修改的页面
↓
子进程完成写入
↓
子进程通知父进程
↓
父进程更新持久化状态
↓
返回 OK 给客户端
详细对比
1. 阻塞范围和时间
SAVE 阻塞
SAVE 开始 ────────────────────── SAVE 结束
[ 主进程 100% 用于写 RDB,无法响应任何请求 ]
↑ 客户端超时 ↑ 恢复
BGSAVE 阻塞(仅 fork 期间)
fork() ──微阻塞── 恢复
[~10-100ms] [主进程正常服务]
2. 对持久化状态的影响
# SAVE 后
redis-cli INFO Persistence | grep rdb_last_save_time
# rdb_last_save_time:1700000001
# BGSAVE 后
redis-cli INFO Persistence | grep rdb_bgsave_in_progress
# rdb_bgsave_in_progress:1 → 进行中
# rdb_bgsave_in_progress:0 → 已完成
redis-cli LASTSAVE
# (integer) 1700000002
3. 执行中的状态检查
# 检查是否有 BGSAVE 在执行
redis-cli INFO Persistence | grep -E "rdb_bgsave|rdb_changes"
# 查看进行中的 RDB 子进程
ps aux | grep "redis-rdb-bgsave"
使用场景对比
SAVE 的适用场景
- Redis 关机前保存数据
redis-cli SAVE
redis-cli SHUTDOWN
# 先 SAVE 确保数据不丢失,再关机
- 低流量维护窗口
# 凌晨 3 点停服维护
redis-cli SAVE
# 确保写 RDB 时不产生增量数据
- 内存紧张场景
# 系统内存不足,无法 fork
redis-cli SAVE # 直接写 RDB,不需要额外内存
vs
redis-cli BGSAVE # fork 需要复制页表,COW 可能额外消耗内存
BGSAVE 的适用场景
- 生产环境定期备份
crontab -e
0 * * * * redis-cli BGSAVE # 每小时备份,不影响业务
- 日常运维操作
# 任何时候需要备份都可以执行
redis-cli BGSAVE
- 复制初始化
# 主库会自动 BGSAVE 给新从库同步
# 不需要人工干预
关键影响因素
fork 耗时
fork 耗时与内存大小有关:
经验值(AWS EC2 实测):
1GB → fork 约 1-5ms
10GB → fork 约 10-50ms
50GB → fork 约 100-300ms
100GB → fork 约 500ms-2s
优化 fork 耗时
# 1. 启用 THP(透明大页)警告
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 2. 设置 vm.overcommit_memory
sysctl vm.overcommit_memory=1
# 3. 增大 vm.max_map_count
sysctl vm.max_map_count=262144
# 4. 选择合适的 Redis 实例规格
# 单实例建议不超过 50GB
并发执行限制
# BGSAVE 不能与 BGREWRITEAOF 同时执行
# 如果已经有一个 BGSAVE 在执行:
redis-cli BGSAVE
# (error) ERR Background save already in progress
# 检查是否有子进程
redis-cli INFO Persistence | grep aof_rewrite_in_progress
redis-cli INFO Persistence | grep rdb_bgsave_in_progress
# 如果同时触发,根据执行顺序:
# - BGSAVE 先执行:BGREWRITEAOF 会延迟
# - BGREWRITEAOF 先执行:BGSAVE 需要等待
场景实践
关机脚本
#!/bin/bash
# 安全关机脚本
echo "Saving RDB..."
redis-cli SAVE
if [ $? -eq 0 ]; then
echo "RDB saved successfully"
else
echo "SAVE failed!"
exit 1
fi
echo "Shutting down..."
redis-cli SHUTDOWN
生产环境备份脚本
#!/bin/bash
# BGSAVE + 等待完成
redis-cli BGSAVE
if [ $? -ne 0 ]; then
echo "BGSAVE 触发失败"
exit 1
fi
# 等待完成
while [ "$(redis-cli INFO Persistence | grep rdb_bgsave_in_progress | cut -d: -f2)" = "1" ]; do
sleep 1
done
echo "BGSAVE completed!"
echo "Last save time: $(date -d @$(redis-cli LASTSAVE))"
面试要点
- 核心区别:SAVE 阻塞 VS BGSAVE 非阻塞
- fork 是关键:BGSAVE 的 fork 可能导致短暂阻塞
- 内存注意:SAVE 不额外耗内存,BGSAVE 有 COW 开销
- 使用建议:生产用 BGSAVE,关机前用 SAVE
- 并发限制:BGSAVE 和 BGREWRITEAOF 不能同时执行
- 统计信息:用 INFO Persistence 查看状态
- 大实例:50GB 以上注意 fork 耗时和 COW 内存
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


暂无评论内容