redis禁止bgsave和bgrewriteaof同时运行,是为避免fork子进程、内存拷贝、序列化及磁盘写入叠加引发的i/o与cpu过载,防止响应延迟激增或oom崩溃。

为什么 BGSAVE 和 BGREWRITEAOF 不能同时运行
Redis 明确禁止 BGREWRITEAOF 和 BGSAVE 并发执行——不是因为技术上做不到,而是出于磁盘 I/O 和 CPU 负载的保守控制。当 BGREWRITEAOF 正在运行时,任何新发来的 BGSAVE 请求都会被服务器直接拒绝(返回 ERR Background save already in progress);反之,若 BGSAVE 已启动,BGREWRITEAOF 会被排队等待其结束。
关键点在于:两个子进程都涉及大量内存拷贝(fork 后的 copy-on-write)、数据序列化和磁盘写入。哪怕单个操作已足够吃资源,叠加后极易触发系统负载飙升、响应延迟激增,甚至 OOM killer 干掉 Redis 进程。
-
BGSAVE写的是全量内存快照(dump.rdb),格式紧凑、二进制、不可读 -
BGREWRITEAOF写的是重写后的 AOF 日志(如appendonly.aof),本质是把当前内存状态“翻译”成最小等效命令集,仍为文本协议格式 - 两者 fork 的时机相同,但后续工作负载类型不同:RDB 侧重内存遍历与二进制编码;AOF 重写需解析键值类型、生成命令、处理过期逻辑,CPU 更敏感
触发后实际发生了什么:从 fork 到文件落地
无论是 BGSAVE 还是 BGREWRITEAOF,第一步都是父进程调用 fork() 创建子进程。此时子进程获得父进程内存页的只读副本(COW 机制),后续所有写操作才会触发页复制。
区别出现在 fork 之后:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
BGSAVE子进程直接遍历整个redisDb.dict,将每个键值对按 RDB 协议编码写入临时文件(如temp-123.rdb),完成后原子替换dump.rdb -
BGREWRITEAOF子进程不读原 AOF 文件,而是重新扫描内存中所有键,逐个生成等效命令(如SET、RPUSH),并自动跳过已过期或被覆盖的中间状态;最终写入新 AOF 文件(如temp-rewrite.aof),再原子替换旧文件 - 二者都依赖
fsync确保落盘,但 RDB 通常只在写完后 fsync 一次;AOF 重写过程中可能分段 fsync,取决于配置的appendfsync策略(即使重写本身不直接受其影响)
配置项如何影响它们的行为
这两个命令本身无参数,但它们是否被触发、何时触发、能否成功,高度依赖 redis.conf 中的配置联动:
-
save 900 1这类规则只驱动BGSAVE,对BGREWRITEAOF完全无效 -
auto-aof-rewrite-percentage和auto-aof-rewrite-min-size仅控制BGREWRITEAOF的自动触发,前提是appendonly yes -
rdbcompression yes会影响BGSAVE生成的 RDB 文件体积和 CPU 开销,但不影响BGREWRITEAOF -
no-appendfsync-on-rewrite yes是关键开关:设为yes时,AOF 重写期间会暂停主线程的appendfsync,避免磁盘争抢;但若此时发生宕机,AOF 缓冲区未刷盘的部分会丢失
注意:save "" 可禁用所有自动 BGSAVE,但不会阻止手动执行或主从同步触发的 BGSAVE。
常见误用场景与错误信号
线上最容易踩的坑,往往藏在看似无害的操作组合里:
- 在监控脚本中轮询执行
LASTSAVE同时又高频调用BGSAVE,可能因前一个未结束而反复收到ERR Background save already in progress,却误判为服务异常 - 开启 AOF 后又配置了
save规则,导致 RDB 和 AOF 两套机制都在后台活跃,磁盘写入压力翻倍,尤其在小内存机器上容易触发 swap - 执行
redis-cli --bigkeys或redis-cli --memkeys时,若恰好撞上BGREWRITEAOF,可能因子进程占用大量内存导致 fork 失败(Cannot allocate memory),进而阻塞主线程 -
CONFIG SET appendonly yes动态开启 AOF 后,Redis 不会自动触发首次BGREWRITEAOF,必须手动执行或等满足重写条件——这点常被忽略,导致 AOF 文件从空开始累积,体积暴涨
真正要盯住的不是命令本身,而是子进程生命周期、磁盘 I/O 队列深度、以及 INFO persistence 中的 rdb_bgsave_in_progress 和 aof_rewrite_in_progress 字段值。










