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