Redis BGSAVE 与 SAVE 的区别

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 的适用场景

  1. Redis 关机前保存数据
redis-cli SAVE
redis-cli SHUTDOWN
# 先 SAVE 确保数据不丢失,再关机
  1. 低流量维护窗口
# 凌晨 3 点停服维护
redis-cli SAVE
# 确保写 RDB 时不产生增量数据
  1. 内存紧张场景
# 系统内存不足,无法 fork
redis-cli SAVE  # 直接写 RDB,不需要额外内存
vs
redis-cli BGSAVE  # fork 需要复制页表,COW 可能额外消耗内存

BGSAVE 的适用场景

  1. 生产环境定期备份
crontab -e
0 * * * * redis-cli BGSAVE  # 每小时备份,不影响业务
  1. 日常运维操作
# 任何时候需要备份都可以执行
redis-cli BGSAVE
  1. 复制初始化
# 主库会自动 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
喜欢就支持一下吧
点赞14 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容