Redis 的 RDB fork 时为什么会产生内存膨胀

很多同学在面试中被问到 Redis 持久化时,都能答出 RDB 和 AOF 的区别,但一旦面试官追问:“RDB 在 fork 子进程时,为什么会导致内存膨胀?” 不少人就开始含糊了。有人说是因为写时复制(Copy-On-Write)本身就会复制内存,也有人说是 fork 本身会拷贝页表。这些说法都不够准确。今天我们就从 Linux fork 的底层机制出发,把这个问题彻底讲清楚。

一、先明确一个前提:fork 并不复制物理内存

在 Linux 中,fork() 创建子进程时,并不会立刻把父进程的物理内存全部复制一份。相反,内核采用了 写时复制(Copy-On-Write,COW) 机制:

  • 父进程和子进程最初共享同一份物理内存页。
  • 内核只复制页表(Page Table),让子进程的虚拟地址指向相同的物理页。
  • 这些共享的物理页被标记为只读
  • 当任意一方尝试写入某个页时,CPU 触发缺页异常,内核才为该页分配新的物理内存,并复制原页内容。

所以,fork 的瞬间并不会导致物理内存翻倍,真正被复制的只是页表。那为什么 Redis 做 RDB 时,内存会明显膨胀呢?关键在于 Redis 在 fork 之后仍然在持续处理写请求

二、内存膨胀的根源:COW 页复制

RDB 持久化的流程是:

  1. 主进程 fork 出一个子进程。
  2. 子进程负责把当前内存中的数据快照写入磁盘。
  3. 主进程继续处理客户端请求,不阻塞

问题就出在第 3 步。子进程在遍历内存写 RDB 文件的过程中,主进程可能正在执行写命令(SET、DEL、LPUSH 等)。一旦主进程写入某个内存页,COW 机制就会触发:

  • 内核为主进程分配一个新的物理页。
  • 把旧页的内容复制到新页。
  • 主进程在新页上修改。
  • 子进程仍然读取旧页,从而保证快照的一致性。

每发生一次这样的写操作,就会多出一份物理内存。 如果 fork 期间写入非常频繁,被复制的页就会越来越多,Redis 占用的物理内存就会不断攀升。这就是所谓“内存膨胀”的本质。

三、内存膨胀到底能有多大?

理论上,最坏情况下,主进程在 fork 期间修改了所有内存页,那么内存占用会接近翻倍。当然实际中很少这么极端,但以下几种情况会显著放大膨胀:

  • 写入量巨大:比如大量 SET、过期删除、LRU 淘汰,都会触发页复制。
  • 内存页数量多:Redis 实例内存越大,页表越大,COW 复制的潜在页数也越多。
  • 透明大页(THP)开启:THP 会把多个 4KB 页合并成 2MB 大页。一旦触发 COW,复制的是整个 2MB,而不是 4KB,内存膨胀会被成倍放大。这也是 Redis 官方建议关闭 THP 的重要原因。
  • fork 耗时过长:内存越大,页表复制越慢,fork 阻塞主进程的时间也越长,期间积压的写请求在 fork 完成后集中执行,进一步加剧 COW。

四、面试常见追问

追问 1:fork 时复制页表本身会占内存吗?

会,但通常很小。页表大小与虚拟内存规模相关,一般每个页表项几字节,相对于数据本身可以忽略。真正的大头是 COW 导致的物理页复制。

追问 2:为什么子进程不直接读主进程内存,而非要 COW?

因为要保证快照一致性。如果子进程直接读主进程正在修改的内存,写出的 RDB 文件可能包含“半新半旧”的数据,恢复时数据就乱了。COW 让子进程始终看到 fork 那一刻的内存视图。

追问 3:如何缓解 RDB fork 的内存膨胀?

  • 关闭透明大页(THP)。
  • 控制单实例内存,避免过大(建议 10GB 以内,视业务而定)。
  • 合理配置 save 策略,避开写入高峰。
  • 使用主从架构,在从节点做 RDB,减轻主节点压力。
  • 考虑混合持久化或 AOF,减少全量 fork 的频率。

追问 4:COW 期间内存膨胀会导致 OOM 吗?

会。如果系统可用内存不足,COW 复制新页时可能触发 OOM Killer,把 Redis 进程杀掉。所以生产环境要预留足够内存,通常建议预留 50% 以上。

五、总结

一句话概括:RDB fork 本身不复制物理内存,但 fork 之后主进程的写操作会触发 COW,导致被修改的内存页被复制,从而产生内存膨胀。 膨胀程度取决于 fork 期间的写入量和内存页大小,最坏情况下接近翻倍。理解这一点,不仅能答好面试题,也能帮助你在生产环境中正确规划 Redis 的内存和持久化策略。

未经允许不得转载:任鹏个人博客 » Redis 的 RDB fork 时为什么会产生内存膨胀

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏