bigywater.tech
常见报错 · 11

Redis OOM command not allowed when used memory > 'maxmemory':哪些命令被拒,volatile-lru 在没有 TTL 时照样 OOM

“OOM command not allowed when used memory > ‘maxmemory’” 说的是 Redis 用掉的内存超过了 maxmemory,并且当前的淘汰策略没有办法腾出空间。这篇在本机用 20 MB 的上限复现它,看清楚被拒绝的是哪些命令、DEL 能不能救、以及 allkeys-lru、volatile-lru 这些策略在同样的写入下到底有什么区别。

24910
noeviction 下写 40000 个 1 KB key,到 maxmemory 之后被拒绝的写入次数(成功 15090 个)
9 / 8
OOM 状态下被拒绝的命令 9 类,照常执行的读 / 删 / 改过期 / 发布 8 类
14900 / 0
volatile-lru 在 key 没有 TTL 时的 OOM 次数 14900,key 带 TTL 时 0;allkeys-lru 也是 0

复现与上限的含义

实测 · 本机执行输出
  写了 40000 个 1 KB 的 key:成功 15090 个,报错 24910 个
  第一条错误: OOM command not allowed when used memory > 'maxmemory'.
  DBSIZE = 15090,used_memory = 20995392,maxmemory = 20971520,used_memory - maxmemory = 48560
  maxmemory-policy = noeviction

noeviction 下内存到上限后写命令被拒绝,used_memory 会略微超过 maxmemory。

哪些命令被拒绝

实测 · 本机执行输出
  SET a 1                    OOM 被拒绝
  INCR cnt                   OOM 被拒绝
  APPEND k0 x                OOM 被拒绝
  LPUSH l 1                  OOM 被拒绝
  HSET h f v                 OOM 被拒绝
  SADD s 1                   OOM 被拒绝
  ZADD z 1 a                 OOM 被拒绝
  SET k0 y(覆盖已有 key)         OOM 被拒绝
  EXPIRE k1 3600             成功
  RENAME k2 k2b              成功
  GET k0                     成功
  EXISTS k0                  成功
  PUBLISH ch msg             成功
  EVAL 只读脚本                  成功
  EVAL 写脚本                   OOM 被拒绝
  DEL k3                     成功
  UNLINK k4                  成功

会增加内存的命令和写脚本被拒绝;读、DEL、UNLINK、EXPIRE、PUBLISH 照常。所以紧急情况下可以 DEL / UNLINK 腾空间。

腾空间与超大 value

实测 · 本机执行输出
  DEL 2000 个 key:used_memory 21240352 -> 18611760,SET a 1 -> "OK"
  再写 4000 个 1 KB 的 key:成功 1786,报错 2214
  FLUSHALL 之后 used_memory = 933904
  内存几乎是空的,SET 一个 30 MB 的 value(maxmemory 只有 20 MB)-> (error) OOM command not allowed when used memory > 'maxmemory'.;used_memory = 945824
  紧接着 SET small 1 -> "OK"
  DEL big 之后 SET small 1 -> "OK"

DEL 一批 key 后写入立刻恢复,但很快又会写满。比 maxmemory 还大的单个 value 即使在空实例上也被拒绝。

不同淘汰策略

实测 · 本机执行输出
  策略                              写成功  报 OOM   剩余 key    淘汰数  最早 1000 个还剩  最晚 1000 个还剩
  noeviction                    15100  14900    15100      0         1000            0
  allkeys-lru                   30000      0    15077  14941          457          949
  allkeys-lfu                   30000      0    15077  14941          460          949
  allkeys-random                30000      0    15063  14956          409          960
  volatile-lru(key 没有 TTL)      15100  14900    15100      0         1000            0
  volatile-lru(key 带 TTL)       30000      0    14768  15250          461          937
  volatile-ttl(key 带 TTL)       30000      0    14680  15338           18         1000

allkeys-* 在同样写入下不再报 OOM;volatile-* 只会淘汰带 TTL 的 key,没有 TTL 的数据一样 OOM。近似 LRU / LFU 会误删较新的 key。

分步演示

内存到上限
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / MySQL 26.10.0 与 Redis 8.10.2(Homebrew,每个实验自己起实例,端口 9150 以上,只监听 127.0.0.1,不碰本机已有的实例)/ Python 3.15.0 + PyMySQL(按各篇注明用到哪些及版本);报错文本都是真实复现时原样捕获的;计时用 time.perf_counter,数字每次运行会有小幅抖动。本篇用一个自己起的 Redis 8.10.2 实例(端口 8120,maxmemory 20mb),纯标准库 RESP 客户端;每个 value 1 KB,key 形如 k0 到 k29999;每种策略前先 FLUSHALL 并 CONFIG RESETSTAT
    • 没有验证:单个 30 MB 参数被拒绝的具体原因(推测与客户端查询缓冲占用内存有关,没有单独验证);maxmemory-samples 对近似 LRU / LFU 精度的影响;复制缓冲区、客户端输出缓冲占用 used_memory 时的表现;内存碎片率(mem_fragmentation_ratio)与 RSS 超过 maxmemory 的情形;Cluster 中某个分片 OOM 的表现;lazyfree 参数对淘汰的影响
    京ICP备2026067502号-1京公网安备11010502063487号