Skip to content

P51 Redis 明明配置了 LRU 为啥还会 OOM ​

面试题:Redis 配了 maxmemory + LRU 淘汰策略,为什么还会报 OOM?

1. 前提:LRU 淘汰只在达到 maxmemory 后才触发 ​

ini
maxmemory 512mb
maxmemory-policy allkeys-lru

只有 Redis 已用内存达到 maxmemory 时才会触发淘汰。如果:

  • 还没到 maxmemory,写不进去是因为单次写入太大;
  • 或者淘汰策略配置不对,就会 OOM。

2. 常见原因 ​

① maxmemory-policy 设置成了 noeviction(默认) ​

noeviction 表示内存满了不淘汰任何 key,新写入直接报错(OOM 错误)。这是最常见的原因——配了 maxmemory 却没配淘汰策略。

② 大 key / 大对象瞬时写入 ​

一次写入一个超大对象(如几十 MB 的 value),当前剩余内存不够,淘汰来不及腾出空间就报错。

③ 内存碎片 / 复制积压缓冲区等"隐藏"内存 ​

  • 客户端输出缓冲区、复制积压缓冲区(repl-backlog)、AOF 重写缓冲都不受 maxmemory 精确限制;
  • 内存碎片(used_memory_rss 远大于 used_memory)会让实际占用超限。

④ 淘汰是"近似 LRU",不是精确 LRU ​

Redis 的 LRU 是采样近似实现(默认 samples=5),采样池里挑最久未用的淘汰,可能误淘汰热数据或没淘汰到该淘汰的,但一般不会直接导致 OOM。

⑤ 多个实例/子进程内存 ​

  • AOF/RDB 持久化子进程(fork)会占用额外内存(Copy-on-Write);
  • 集群多实例部署在同一台机器,共享物理内存,单个实例没到 maxmemory 但机器内存已满。

3. 排查思路 ​

bash
INFO memory
# 看 used_memory / used_memory_rss / maxmemory / 碎片率
bash
CONFIG GET maxmemory-policy   # 确认不是 noeviction
  • 检查有没有大 key(redis-cli --bigkeys);
  • 检查持久化配置和子进程内存;
  • 看碎片率,必要时 MEMORY PURGE 或重启。

4. 解决 ​

  • 配置合理的淘汰策略:allkeys-lru(全部 key)/ volatile-lru(只淘汰带 TTL 的);
  • 拆分/控制大 key;
  • 调大 maxmemory 或加实例;
  • 开启 maxmemory-policy 的同时给 key 设 TTL;
  • 监控 used_memory_rss 和碎片率。

一句话总结 ​

Redis OOM 最常见是 maxmemory-policy 默认 noeviction(满了不淘汰、新写入报错);其次是瞬时大 key、内存碎片、fork 子进程和复制缓冲等超限内存;先用 INFO memory + CONFIG GET maxmemory-policy 排查,再配好淘汰策略、控大 key、留内存余量。

基于 VitePress 重建