fork 与内核内存策略
Linux 的 overcommit 策略决定内核是否允许进程承诺超过物理内存的地址空间。Redis 做后台快照和 AOF 重写都要 fork 子进程,fork 瞬间需要复制父进程的页表;即使有写时复制机制,内核也要先通过这一层检查。当 vm.overcommit_memory 处于严格模式时,大实例的 fork 可能被直接拒绝,日志里出现 fork: Cannot allocate memory,后台保存就此失败,数据保护链条断在这里,而磁盘可能还有大量空间。
基本信息
| 建议取值 | vm.overcommit_memory=1 |
|---|---|
| 典型症状 | 日志出现 Can't save in background: fork: Cannot allocate memory |
| 生效方式 | sysctl -w 临时生效,写入 /etc/sysctl.conf 永久生效 |
| 查看方式 | sysctl vm.overcommit_memory |
| 影响范围 | 手动 BGSAVE、AOF 重写、主从全量同步的 fork 环节 |
典型使用场景
- 新机器上线 Redis 前,把内核参数纳入部署基线检查
- 出现「快照偶尔失败但磁盘还有空间」时,优先排查这一项
- 内存较大的实例(几十 GB 以上)把该参数固化进部署文档
- 容器化部署时确认宿主机参数,容器内通常改不动这项
- 主从全量同步失败的排查清单里一并核对 fork 相关日志
查看与设置
查看与设置
sysctl vm.overcommit_memory # 查看当前值:0 启发式、1 总是允许、2 严格
sysctl -w vm.overcommit_memory=1 # 临时生效,用于验证效果
echo 'vm.overcommit_memory=1' >> /etc/sysctl.conf # 永久生效
sysctl -p # 重载配置文件
redis-cli BGSAVE # 复现验证:后台保存是否能正常完成
redis-cli INFO stats | grep latest_fork_usec # 结合 fork 耗时一起观察
grep -i 'Cannot allocate' /var/log/redis/redis-server.log # 对照历史日志三种取值对照
| 取值 | 含义 | 对 Redis 的影响 |
|---|---|---|
| 0 启发式 | 内核按经验估算是否允许 | 大实例的 fork 可能被拒绝 |
| 1 总是允许 | 不做过度承诺检查 | 官方推荐,fork 不再卡在这一层 |
| 2 严格 | 承诺量不得超过限额 | 最容易出现 fork 失败 |
| 改完必做 | 重启或重新触发一次后台保存 | 否则无法确认是否真的解决 |
把该值设为 1 并不改变真实内存占用,只是让 fork 时的地址空间检查不再直接失败;写时复制产生的内存峰值仍然需要真实的空闲内存或 swap 支撑,因此监控上不能因为改了参数就放松内存余量告警。