在 Redis 中,BGREWRITEAOF
是一个用于重写 AOF(Append Only File)文件的后台操作,目的是压缩 AOF 文件,去除冗余命令,从而减小文件体积并提升恢复速度。然而,在执行 BGREWRITEAOF
期间,主进程仍在处理客户端请求,可能会产生新的写入操作。这就带来了一个潜在问题:主进程与子进程(BGREWRITEAOF 子进程)之间可能出现数据不一致。
问题本质:主进程与子进程的数据不一致
- 主进程:正常处理写操作,将命令追加到 AOF 缓冲区,并可能写入 AOF 文件。
- 子进程(BGREWRITEAOF):在某一时刻(通常是
BGREWRITEAOF
命令执行时)启动,它会读取当前 Redis 的完整数据集(内存中的键值对),并将其以命令形式写入一个新的 AOF 文件。 - 问题:在子进程执行期间,主进程可能已经接收并处理了新的写操作,这些写操作没有被子进程看到,导致新 AOF 文件中缺少这部分数据。
Redis 如何解决这个问题?
Redis 采用了一种称为 “AOF 重写缓冲区”(AOF rewrite buffer) 的机制来解决这一问题。
✅ 核心机制:AOF 重写缓冲区(AOF Rewrite Buffer)
子进程启动时:
- Redis 主进程会创建一个新的 AOF 文件(临时文件,如
temp-rewriteaof-bg-*.aof
)。 - 子进程开始读取内存中的数据集,并将所有键值对以命令形式写入这个新文件。
- Redis 主进程会创建一个新的 AOF 文件(临时文件,如
主进程在子进程运行期间:
- 所有新的写操作(如
SET key value
)不仅写入 AOF 缓冲区,还会额外写入一个特殊的缓冲区 —— AOF 重写缓冲区。 - 这个缓冲区是独立的,用于记录子进程运行期间的增量操作。
- 所有新的写操作(如
子进程完成重写后:
- 子进程退出。
- 主进程将 AOF 重写缓冲区中的所有命令追加写入到新 AOF 文件末尾。
- 然后将新 AOF 文件原子替换为旧的 AOF 文件(通过
rename
系统调用)。
最终结果:
- 新的 AOF 文件包含了:
- 子进程重写时的完整数据集(即快照)。
- 子进程运行期间所有新增的写操作。
- 因此,新 AOF 文件是完整且一致的,能完整恢复 Redis 的状态。
- 新的 AOF 文件包含了:
关键点
机制 | 作用 |
---|---|
AOF 重写缓冲区 | 缓存子进程运行期间的增量写操作 |
子进程读内存快照 | 生成 AOF 的基础数据(无冗余命令) |
主进程追加缓冲区内容 | 确保不丢失子进程运行期间的写操作 |
原子替换文件 | 保证 AOF 文件切换的原子性和一致性 |
注意事项
AOF 重写缓冲区大小有限:
- 如果缓冲区溢出(例如写入太频繁),Redis 会阻塞主进程,直到子进程完成或缓冲区清空。
- 可通过配置
aof-rewrite-incremental-fsync
和aof-rewrite-buffer-size
调优。
性能影响:
BGREWRITEAOF
是 CPU 密集型操作,可能影响主进程性能。- 建议在低峰期执行,或使用
auto-aof-rewrite
自动触发。
AOF 重写期间主进程仍可服务:
- 重写过程是异步的,主进程不阻塞(除了缓冲区满时可能阻塞)。
示例流程
1 | # 主进程执行 BGREWRITEAOF |
✅ 总结
Redis 通过 AOF 重写缓冲区 机制,完美解决了 BGREWRITEAOF
与主进程数据不一致的问题:
子进程负责“快照”,主进程负责“增量”,最后合并,确保 AOF 文件完整、一致、可恢复。