编程笔记

lifelong learning & practice makes perfect

redis|为了优化AOF文件大小使用异步线程BGREWRITEAOF重写日志文件,redis是如何解决数据不一致的?

在 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)

  1. 子进程启动时

    • Redis 主进程会创建一个新的 AOF 文件(临时文件,如 temp-rewriteaof-bg-*.aof)。
    • 子进程开始读取内存中的数据集,并将所有键值对以命令形式写入这个新文件。
  2. 主进程在子进程运行期间

    • 所有新的写操作(如 SET key value)不仅写入 AOF 缓冲区,还会额外写入一个特殊的缓冲区 —— AOF 重写缓冲区
    • 这个缓冲区是独立的,用于记录子进程运行期间的增量操作。
  3. 子进程完成重写后

    • 子进程退出。
    • 主进程将 AOF 重写缓冲区中的所有命令追加写入到新 AOF 文件末尾
    • 然后将新 AOF 文件原子替换为旧的 AOF 文件(通过 rename 系统调用)。
  4. 最终结果

    • 新的 AOF 文件包含了:
      • 子进程重写时的完整数据集(即快照)。
      • 子进程运行期间所有新增的写操作。
    • 因此,新 AOF 文件是完整且一致的,能完整恢复 Redis 的状态。

关键点

机制 作用
AOF 重写缓冲区 缓存子进程运行期间的增量写操作
子进程读内存快照 生成 AOF 的基础数据(无冗余命令)
主进程追加缓冲区内容 确保不丢失子进程运行期间的写操作
原子替换文件 保证 AOF 文件切换的原子性和一致性

注意事项

  1. AOF 重写缓冲区大小有限

    • 如果缓冲区溢出(例如写入太频繁),Redis 会阻塞主进程,直到子进程完成或缓冲区清空。
    • 可通过配置 aof-rewrite-incremental-fsyncaof-rewrite-buffer-size 调优。
  2. 性能影响

    • BGREWRITEAOF 是 CPU 密集型操作,可能影响主进程性能。
    • 建议在低峰期执行,或使用 auto-aof-rewrite 自动触发。
  3. AOF 重写期间主进程仍可服务

    • 重写过程是异步的,主进程不阻塞(除了缓冲区满时可能阻塞)。

示例流程

1
2
3
4
5
6
7
8
# 主进程执行 BGREWRITEAOF
BGREWRITEAOF

# 1. 子进程启动,读取内存快照,写入 temp-rewriteaof-bg-*.aof
# 2. 主进程开始写入 AOF 文件 + AOF 重写缓冲区
# 3. 子进程完成,退出
# 4. 主进程将重写缓冲区内容追加到新 AOF 文件
# 5. 原 AOF 文件被 rename 为 backup,新文件替换它

✅ 总结

Redis 通过 AOF 重写缓冲区 机制,完美解决了 BGREWRITEAOF 与主进程数据不一致的问题:

子进程负责“快照”,主进程负责“增量”,最后合并,确保 AOF 文件完整、一致、可恢复。

欢迎关注我的其它发布渠道