根本原因是vm.overcommit_memory=2时内核严格校验内存不足,导致fork()因total_vm远超RSS而预留失败;应设为1并调低swappiness至1。

Redis 在低内存环境下 RDB 失败,根本不是磁盘或权限问题,而是 fork() 调用被内核直接拒绝 —— 因为它申请的是虚拟内存预留空间,不是实际物理内存。
fork() 失败时日志里最典型的错误是什么
你看到的报错通常长这样:
13245:M 06 May 12:45:22.102 # Can't save in background: fork: Cannot allocate memory
或者启动时就有警告:
WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.
这类错误出现时,df -h 显示磁盘充足,ls -ld 确认目录有写权限,redis-cli INFO persistence 中 rdb_bgsave_in_progress 始终为 0,rdb_last_bgsave_status 是 err。这基本可以排除磁盘、路径、配置项错误,直指系统级 fork 限制。
为什么 total_vm 远大于 RSS 却导致 fork 失败
Redis 主进程的 total_vm(虚拟内存总量)常是 RSS(实际驻留物理内存)的 2–3 倍,尤其在使用大量小对象、碎片化分配或开启透明大页时。而 Linux 内核在 vm.overcommit_memory = 2(Debian/Ubuntu 默认)下会严格检查:
- 可用物理内存 + swap ≥ 当前进程
total_vm - 哪怕实际只用了 3GB
RSS,但total_vm报 8GB,内核就认为“没足够空间预留”,直接返回ENOMEM
这不是 Redis 的 bug,是内核对 COW(Copy-On-Write)机制的保守策略:它得为子进程可能修改的每一页都预留虚拟地址空间。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
vm.overcommit_memory=1 能解决问题,但要注意 swappiness
把 vm.overcommit_memory 改成 1 后,内核不再校验总和,只按“启发式规则”允许 fork(即:只要不明显超限就放行),这是 Redis 官方文档明确推荐的做法。
但光改这一项还不够,还得同步调低 swappiness:
- 执行
sysctl vm.swappiness=1(避免频繁 swap 影响 fork 性能) - 写入
/etc/sysctl.conf持久化:vm.overcommit_memory = 1和vm.swappiness = 1 - 注意:不要设
swappiness=0,Linux 4.0+ 内核下它会禁用 swap,反而让 OOM killer 更激进
改完后无需重启 Redis,sysctl -p 生效即可立即尝试 redis-cli BGSAVE。
RDB 文件为空(0MB)时,优先排查 fork 而不是磁盘
如果 dump.rdb 生成了但大小为 0,别急着删日志或 chmod,先做三件事:
- 运行
dmesg -T | grep -i "out of memory\|fork",看内核是否已 kill 过 redis 子进程 - 查
/proc/$(pidof redis-server)/status,确认VMSize(即total_vm)是否远超当前空闲内存 - 手动触发
redis-cli BGSAVE并立刻ps aux | grep redis,观察子进程是否存在、存活几秒就消失
这些比检查 dir 配置或磁盘空间更接近真实病因 —— 因为 fork 失败时,子进程根本没起来,自然不会写任何字节到文件。
真正卡住人的地方,往往不是 Redis 配置写错了,而是你盯着 redis.conf 逐行核对时,系统内核正默默拒绝每一次 fork 请求。

















