Redis被OOM Killer杀死的根本原因是used_memory持续逼近或突破物理内存上限,导致内核紧急回收失败后直接终结进程;此时淘汰策略已失效,evicted_keys停滞,OOM Killer接管。

Redis 被内核 OOM Killer 杀死,根本原因不是“淘汰慢”,而是 used_memory 持续逼近甚至突破物理内存上限,导致内核在紧急回收失败后直接选中 Redis 进程终结——此时淘汰策略早已失效,evicted_keys 停滞不涨,OOM killer 已接管。
为什么开启 lazyfree-lazy-eviction 仍可能被 kill
很多人开了 lazyfree-lazy-eviction yes 就以为万事大吉,但实际仍被杀,关键在于:该配置只影响“淘汰时释放内存”的方式(从同步变异步),它不阻止内存申请本身触达系统极限。当 Redis 主线程申请新内存页失败、触发 fork() 失败或页分配失败时,内核会绕过 Redis 自身逻辑,直接调用 OOM Killer。
-
fork()失败常见于开启 RDB/AOF 且内存碎片高(mem_fragmentation_ratio > 1.5)时,即使used_memory未满,copy-on-write也会因无法分配足够连续页而失败 -
overcommit_memory = 0(默认)下,内核按“乐观预估”判断是否允许分配,Redis 大量小对象 + 元数据开销容易让内核误判为超限 -
maxmemory设得过于接近总内存(如 31GB 机器设maxmemory 30gb),没给内核缓存、page cache、Redis fork 子进程留余量
必须调整的三个内核参数
仅靠 Redis 配置无法规避内核级干预,以下三项需在 /etc/sysctl.conf 中设置并 sysctl -p 生效:
-
vm.overcommit_memory = 1:关闭内存乐观预估,改为“只要总申请 ≤ 物理内存 + swap 就允许”,避免因 fork 或临时峰值被拒 -
vm.swappiness = 1:强制内核尽量不 swap,但保留最低限度(值为 0 会禁用 swap,反而导致 OOM 更激进;值为 1 是平衡点) -
vm.min_free_kbytes = 65536(约 64MB):确保内核始终保有底线空闲内存,防止因 page cache 突然膨胀挤占 Redis 可用页
注意:vm.overcommit_ratio 在 overcommit_memory = 2 时才生效,不要混用;这里必须用 = 1。
Redis 配置层的硬性约束
内核参数只是兜底,Redis 自身必须守住内存水位红线:
-
maxmemory必须显式设置,且建议 ≤ 总内存的 75%(例如 32GB 机器设maxmemory 24gb),为 fork、page cache、内核元数据留足空间 - 淘汰策略必须匹配 key 生命周期:
volatile-lru或volatile-ttl要求所有写入都带EXPIRE,否则evicted_keys为 0,used_memory持续上涨直至触发 OOM - 禁用
activedefrag(active-defrag-ignore-bytes设为 0):Redis 4.0+ 的内存碎片整理会额外申请内存,高负载下反而加剧压力
验证是否生效:运行 redis-cli INFO memory | grep -E "(used_memory|maxmemory|evicted_keys|mem_fragmentation_ratio)",确认 used_memory 稳定在 maxmemory 90% 以下,且 evicted_keys 持续增长。
最易被忽略的监控盲区
很多人盯着 used_memory_human,却漏看两个致命指标:
-
mem_allocator:若为jemalloc,要检查INFO memory中allocator_active和allocator_resident是否远大于used_memory——说明 jemalloc 缓存了大量未归还的内存,需调allocator_conf或重启 -
process_rss:RSS 值(进程实际占用物理内存)若持续高于maxmemory1.5 倍,说明元数据或碎片已失控,光调maxmemory无用
真正安全的边界不是 maxmemory,而是 process_rss < 总内存 × 0.7 —— 这个数字必须实时盯住,不能只信配置文件里的那行 maxmemory。


















