aof重写期间新命令同时写入原aof缓冲区(aof_buf)和重写专用内存缓冲区(aof_rewrite_buf_blocks),后者通过匿名管道实时同步给子进程,最终追加至新aof文件末尾,确保不丢失但依赖父子进程协同。

Redis AOF重写期间新增的写入数据不会丢失,也不会直接写入新AOF文件,而是通过「双缓冲 + 管道同步」机制暂存并最终追加——但这个过程容易被误解为“写入老文件就完事了”,实际不是。
重写期间新命令到底写到哪了
当执行 BGREWRITEAOF 后,主进程仍持续接收写请求。这些新命令会同时做两件事:
- 追加到原AOF文件的内存缓冲区
aof_buf,后续按appendfsync策略落盘(保障老AOF不丢) - 追加到专用的重写缓冲区
aof_rewrite_buf_blocks(一个链表结构的内存缓冲区),供子进程消费
注意:aof_rewrite_buf_blocks 是纯内存结构,不落地、不刷盘,只用于父子进程间传递增量。它和 aof_buf 是两个独立缓冲区,不能混用或互相替代。
子进程怎么拿到重写期间的新数据
子进程启动后,主进程会通过一对匿名管道(pipe)向其发送增量命令。关键点在于:
- 管道写端由父进程持有,读端由子进程持有;子进程在重写完内存快照后,会阻塞读取管道中剩余数据
- 父进程在子进程即将完成前,会停止往管道写入新命令(避免无限积压),但仍在继续更新
aof_buf和aof_rewrite_buf_blocks - 子进程读完管道数据后,将这部分命令追加到临时AOF文件末尾(即
temp-rewriteaof-bg-*.aof),再原子 rename 替换旧文件
也就是说:子进程不读磁盘、不读老AOF文件,只读自己 fork 时刻的内存快照 + 父进程实时推送的管道数据。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
为什么不会丢数据,但可能有延迟风险
数据不丢的前提是:父进程没崩溃、管道没满、子进程能成功读完并写入。但以下情况会导致问题:
-
aof_rewrite_buf_blocks无大小限制,若重写耗时长 + 写入量大,可能吃光内存(OOM) - 父进程往管道写数据时,若子进程读取慢或卡住,管道缓冲区填满后
write()会阻塞父进程,拖慢所有客户端请求(表现为latency升高、client-output-buffer-limit触发断连) - 子进程退出前未完成追加,或 rename 失败,新AOF文件不可用,Redis 会回退使用旧AOF(日志里报
Failed to rename ...)
所以生产环境必须监控 aof_current_size、aof_base_size 和 latest_fork_usec,避免自动重写在高峰时段触发。
重写完成后,新命令如何切换到新AOF文件
没有“切换”动作。重写完成瞬间,Redis 做三件事:
- 原子 rename 临时文件为正式AOF文件名(如
appendonly.aof) - 清空
aof_rewrite_buf_blocks链表 - 重置
aof_current_size计数器,后续所有新命令只写入这个新文件的aof_buf
老AOF文件被 unlink(但若还有进程打开它,比如备份脚本正在读,它会继续存在直到句柄关闭)。整个过程不涉及“把新命令从老文件搬过去”,那是RDB+AOF混合模式才有的逻辑。
真正容易被忽略的是:重写期间的命令增量全靠内存缓冲和管道传输,既不落盘也不持久化。一旦父进程崩溃,这部分数据就彻底丢失——哪怕子进程已写完快照,只要管道数据没读完、没追加,就不算安全。










