bgsave生成的是fork时刻的内存快照,主线程后续写操作不进入本次RDB,因Linux COW机制使子进程只读取原始页;频繁修改会触发大量页复制,导致内存近翻倍,需监控mem_fork_bytes和RSS变化。

不会同步到本次快照。 bgsave 生成的是 fork 时刻的内存快照,主线程后续所有写操作都不会反映在本次 RDB 文件中——这是由 Linux 的写时复制(Copy-On-Write, COW)机制决定的,不是 Redis 的 bug,而是设计使然。
为什么 bgsave 期间改数据不进快照?
执行 bgsave 时,Redis 主进程调用 fork() 创建子进程。此时子进程与父进程共享物理内存页(只复制页表,不复制数据),但内核将这些页标记为 read-only。一旦主线程尝试修改某个键值对,CPU 触发页错误(page-fault),内核立即为该内存页分配新物理页、复制原内容,再让主线程写入副本——这个过程叫写时复制。
关键点在于:bgsave 子进程始终读取的是 fork 时刻的原始内存页,它看不到、也读不到主线程写入的新副本。所以:
- 主线程改了
user:1001的 age 字段,这次修改只存在于新分配的内存页里 -
bgsave子进程仍在读旧页里的原始值(比如 age=25),并把它写进 RDB - 这个新值(比如 age=28)只能等到下一次
bgsave或 AOF rewrite 才可能落盘
bgsave 期间频繁写可能导致内存翻倍
极端情况下,如果主线程在 bgsave 过程中修改了大量键,而这些键原本分散在不同内存页上,每页修改都会触发一次 COW,导致 Redis 进程总内存占用接近原来的 2 倍。
这在以下场景容易出问题:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 实例内存使用率已超 60%,且配置了
vm.overcommit_memory = 0(Linux 默认) - 单次
bgsave耗时较长(比如 >30 秒),期间有大批量写入(如定时任务刷缓存) - 使用了大 value(如 1MB+ 的 hash 或 string),单个 key 修改就触发整页复制
此时 dmesg 可能出现 Out of memory: Kill process redis-server,不是 Redis 崩溃,而是 OOM Killer 干掉了它。
如何验证当前是否正在发生 COW 内存膨胀?
直接看 Redis 自身指标和系统指标结合判断:
- 执行
INFO memory,重点关注mem_fork_bytes:这是 fork 后子进程实际使用的额外内存字节数,值越大说明 COW 复制越多 - 对比
used_memory_rss和used_memory:如果前者比后者高出 1.5 倍以上,且mem_fork_bytes持续增长,基本确认 COW 正在大量发生 - 查系统级指标:
cat /proc/$(pgrep redis-server)/status | grep VmRSS,观察 fork 前后 RSS 是否激增
注意:mem_fork_bytes 在 Redis 6.0+ 才暴露,老版本需依赖 top -p $(pgrep redis-server) 看 RES 列变化趋势。
生产环境最常被忽略的细节
很多人以为只要用了 bgsave 就“绝对安全”,其实真正危险的是时间窗口错配:
- 自动触发的
save 300 10配置,在流量低谷期(比如凌晨 2 点)刚好撞上业务批量写入任务 - 运维手动执行
bgsave后立刻跑数据迁移脚本,没等子进程退出就发起第二轮写压测 - 主从切换后,新主节点立即开始
bgsave,同时客户端重连并重放大量命令
这些场景下,COW 不是理论风险,而是真实内存尖刺来源。监控不能只盯 used_memory,必须把 mem_fork_bytes 和 latest_fork_usec 加进告警项。

















