根本原因是overcommit_memory=0导致fork时COW触发OOM Killer,必须设为1并配maxmemory+淘汰策略;否则Redis可能因内存耗尽被杀。

Redis进程被OOM Killer杀掉,根本原因不是Redis本身内存超了
系统触发OOM Killer,通常是因为Linux内核发现物理内存+swap即将耗尽,而overcommit_memory设为0(默认)时,内核只在分配内存时粗略估算,不真正检查剩余页框。Redis的fork()操作(如RDB快照、AOF rewrite)会复制父进程页表,虽用写时复制(COW),但若此时Redis已占用大量内存(比如16GB),子进程一碰新页就可能瞬间申请数GB物理内存——此时哪怕Redis自身没超限,系统也扛不住,直接挑RSS最大的进程干掉,Redis首当其冲。
必须改/proc/sys/vm/overcommit_memory为1或2
不改这个,所有Redis内存限制手段都只是“纸面安全”:
-
overcommit_memory = 0:内核按启发式算法预估,高并发+大内存Redis极易误判,最危险 -
overcommit_memory = 1:允许超额分配(只要总申请不超过总虚拟地址空间),适合Redis——它实际使用率远低于maxmemory,且fork()时不会立即占满物理内存 -
overcommit_memory = 2:严格模式,要求CommitLimit = SwapTotal + RAM * overcommit_ratio;需手动算好并配足够swap(不推荐,swap会拖慢Redis)
实操建议:永久生效执行
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf sysctl -p
验证:cat /proc/sys/vm/overcommit_memory 输出应为 1。
Redis端必须配maxmemory + 合理maxmemory-policy
仅靠系统层设置不能防止Redis自己吃光内存,尤其在客户端持续写入、没开淘汰策略时:
-
maxmemory必须显式设置(单位:bytes),例如maxmemory 4gb;不设=不限制,等同于把炸弹交给客户端 -
maxmemory-policy别无脑选noeviction:它只报错不删数据,但OOM Killer不看报错,只看RSS - 生产推荐
allkeys-lru或volatile-lfu:前者均衡,后者适合有TTL的缓存场景;避免volatile-random这种不可控策略 - 注意:AOF rewrite和RDB fork仍会额外消耗内存,
maxmemory应比机器总内存至少留出2~3GB余量
检查swap使用和Redis RSS是否异常逼近物理内存
即使配置正确,也要防“温水煮青蛙”:
- 用
free -h确认SwapUsed接近SwapTotal?是→说明overcommit_memory=2或内存泄漏,立刻查 - 用
ps -o pid,rss,comm -C redis-server看Redis RSS是否持续增长且逼近总内存?是→检查是否有bigkey、未清理的scan游标、或客户端误存全量数据 - Redis日志里搜
Can't save in background: fork: Cannot allocate memory?这是fork()失败的明确信号,说明系统已到临界点
真正棘手的是:overcommit_memory=1能缓解fork失败,但无法阻止Redis因bug或误配置缓慢吃光内存——得靠监控RSS+定期redis-cli info memory | grep used_memory_rss交叉验证。











