在使用云服务器部署Redis的过程中,不少运维人员和开发者都遇到过这样的报错:OOM command not allowed when used memory > 'maxmemory'。这个错误一旦出现,意味着Redis已经无法接受任何写入命令,包括set、hset、lpush等常规操作,业务侧表现为数据写不进去、接口大量报错。要理解并解决这个问题,关键在于弄清楚Redis的内存管理机制,也就是maxmemory参数和各种内存淘汰算法的工作原理。

一、OOM错误是怎么产生的
Redis是一个基于内存的键值数据库,所有数据默认都存放在内存中。maxmemory是Redis配置中的一个重要参数,用来限制Redis实例最大可使用的内存量。当Redis实际占用的内存达到这个上限时,如果淘汰策略设置为noeviction(这也是某些旧版本的默认值),Redis就会拒绝所有可能增加内存占用的写命令,并返回OOM错误。
需要注意的是,即使设置了会主动删除数据的淘汰策略,如果内存中全部是无法被淘汰的键,同样会触发这个错误。比如策略是volatile-lru,但所有键都没有设置过期时间,Redis找不到可以删除的对象,最终还是会拒绝写入。所以说,OOM错误的根本原因有两个:一是maxmemory设置不合理,二是淘汰策略与数据结构不匹配。
另外,云服务器上还可能出现另一种情况:物理内存本身不足,导致系统触发swap甚至OOM Killer直接杀掉Redis进程。这种情况和Redis自身的OOM command not allowed报错是两回事,排查时要先分清楚是Redis内部的内存限制,还是操作系统层面的内存不足。
二、八种内存淘汰策略详解
Redis提供了多种maxmemory-policy可选值,不同版本支持的策略略有差异,常见的有以下八种:
| 策略 | 作用范围 | 淘汰算法 |
|---|---|---|
| noeviction | 所有键 | 不淘汰,内存满时拒绝写入 |
| allkeys-lru | 所有键 | 近似LRU,淘汰最久未访问的键 |
| allkeys-lfu | 所有键 | LFU,淘汰访问频率最低的键(Redis 4.0+) |
| allkeys-random | 所有键 | 随机淘汰任意键 |
| volatile-lru | 设置了过期时间的键 | 近似LRU |
| volatile-lfu | 设置了过期时间的键 | LFU(Redis 4.0+) |
| volatile-random | 设置了过期时间的键 | 随机淘汰 |
| volatile-ttl | 设置了过期时间的键 | 优先淘汰剩余存活时间最短的键 |
从表中可以看出,策略的命名很有规律:前半部分决定候选键的范围,allkeys表示全体键都参与淘汰,volatile表示只有设置了过期时间的键才会被淘汰;后半部分决定选择算法。如果选择了volatile开头的策略,而业务中大量键没有设置TTL,这些键就永远无法被淘汰,内存满了照样报OOM错误,这是实际运维中最常见的坑。
关于LRU算法,Redis并没有实现严格的传统LRU。严格的LRU需要维护一个双向链表,每次访问都要移动节点,内存和CPU开销都比较大。Redis采用的是近似LRU,通过maxmemory-samples参数控制采样数量,默认为5,也就是每次随机抽取5个键,从中淘汰最久未访问的那个。采样数越大,淘汰结果越接近理想LRU,但CPU消耗也越高。
三、如何为业务选择合适的策略
缓存场景是Redis最常见的使用方式。如果Redis中存的纯粹是热点数据缓存,数据丢了可以从数据库重建,推荐使用allkeys-lru或allkeys-lfu。allkeys-lru适合访问模式相对均匀、有明显时间局部性的业务,比如新闻资讯、商品详情页缓存;allkeys-lfu更适合有明显热点分布的业务,比如某些爆款商品或热门话题会被反复访问,LFU能保证这些高频键不被误删。
如果Redis中同时存在缓存数据和不能丢失的业务数据,比如既存session又存一些需要持久化的队列,可以考虑volatile-lru,只让设置了过期时间的缓存数据参与淘汰,未设置过期时间的重要数据则安全无忧。但使用这类策略必须保证缓存键都正确设置了TTL,否则淘汰机制形同虚设。
对于存在明显时效性的数据,比如验证码、限时活动数据,volatile-ttl比较合适,它会优先删除即将过期的键,让内存中保留的数据更有时效性。至于allkeys-random和volatile-random,一般不推荐在生产环境使用,随机删除可能把热点数据删掉,导致缓存命中率大幅下降。noeviction则适合把Redis当作存储系统使用的场景,内存不够时应该通过扩容解决而不是删数据。
四、参数配置与问题排查
配置maxmemory和淘汰策略有两种方式。第一种是修改配置文件redis.conf,添加maxmemory 4gb和maxmemory-policy allkeys-lru两行配置,然后重启实例生效。第二种是通过命令行动态修改,执行config set maxmemory 4294967296和config set maxmemory-policy allkeys-lru,立即生效不需要重启,适合紧急处理线上故障,但重启后失效,记得同步写入配置文件。
出现OOM报错后的排查思路建议按以下顺序:先用info memory命令查看used_memory和maxmemory的值,确认内存是否真的达到了上限;再用dbsize配合scan检查有多少键设置了过期时间,判断当前策略是否有可淘汰的候选键;接着检查业务写入量是否有异常增长,比如是否有大key被写入、是否遭受恶意请求;最后结合业务特点调整策略或扩容内存。排查时还可以关注evicted_keys指标,它表示因内存满而被淘汰的键数量,如果这个数字持续快速增长,说明内存确实吃紧,应该尽早扩容。
此外,maxmemory的设置也要留有余量。云服务器上Redis所在主机还需要内存运行操作系统和Redis进程本身,一般建议maxmemory不超过物理内存的70%到80%,剩下的留给系统、复制缓冲区和fork时的内存开销,避免出现更难排查的系统级问题。
五、总结
OOM command not allowed本质上是Redis内存达到上限后的一种自我保护行为。解决问题的核心不在于消除报错本身,而在于结合业务特点做好内存规划:缓存类业务选择合适的淘汰策略让Redis自动清理冷数据,存储类业务合理评估容量并及时扩容。同时养成给缓存键设置TTL的习惯,定期用info memory和redis-cli --bigkeys监控内存使用情况,才能让Redis在长期运行中保持稳定。
Redis内存溢出maxmemory策略Redis淘汰算法修改时间:2026-09-13 18:14:46