Redis 设置 maxmemory-policy 为 noeviction 后,当内存达到 maxmemory 上限时,队列的写入命令(如 LPUSH、RPUSH、XADD)会直接失败并返回 OOM 错误,但读取命令(如 LPOP、RPOP)通常不受影响。该策略适用于数据绝对不能丢失的核心业务场景,但要求应用层必须具备完善的异常捕获和降级机制。
先说结论:noeviction 策略能防止队列数据因内存不足被自动淘汰,但会导致内存满时写入服务不可用,需配合应用层错误处理。
- 适合场景:金融交易记录、核心业务队列等数据不可丢失场景。
- 先准备:显式配置 maxmemory 具体数值,并确保应用层能捕获 OOM 异常。
- 验收标准:内存超限后写入命令返回 OOM 错误,且现有队列数据未被删除。
命令速用版
生产环境建议在 redis.conf 中持久化配置,避免重启失效。临时验证可使用 CONFIG SET 命令。
# 1. 临时生效(重启后失效)
CONFIG SET maxmemory 2gb
CONFIG SET maxmemory-policy noeviction
# 2. 持久化配置(redis.conf)
maxmemory 2gb
maxmemory-policy noeviction
# 3. 强制重写配置文件(比手动修改更安全)
CONFIG REWRITE为什么会这样
noeviction 策略的核心逻辑是“内存满时拒绝写入”,而不是“自动清理数据”。
当 Redis 的 used_memory 超过 maxmemory 限制时,执行写命令(包括队列的 LPUSH、RPUSH、SADD 等)会触发内存检查逻辑。由于策略设置为不淘汰(noeviction),Redis 不会删除任何旧键来腾空间,而是直接中断当前写操作并返回标准错误信息:(error) OOM command not allowed when used memory > 'maxmemory'。读操作(如 LPOP)不增加内存占用,因此通常可以正常执行,这使得队列表现为“只读不可写”状态。
分步处理
配置 noeviction 不仅是修改参数,还需要应用层和监控的配合,以下是标准落地步骤:
1. 设置内存上限
必须同时设置 maxmemory 和 maxmemory-policy。仅设置策略而 maxmemory 为 0(无限制)时,淘汰策略不会触发。建议将 maxmemory 设为机器总内存的 45%–60%,预留空间给客户端输出缓冲区、Lua 脚本等隐性开销。
2. 应用层异常捕获
客户端必须捕获写入失败异常。例如 Python 的 redis-py 会抛 ResponseError,Node.js 的 ioredis 会抛 ReplyError。捕获后应执行降级逻辑,如切换只读模式、写入本地磁盘或触发告警。
3. 监控配置
监控重点应从 evicted_keys(该策略下恒为 0)转向 OOM 错误频次。需关注 INFO memory 中的 used_memory 峰值,以及 INFO clients 中的 client_longest_output_list,防止输出缓冲区积压导致实际内存超限。
怎么验证是否生效
配置完成后,通过以下三步验证策略是否按预期工作:
1. 检查配置状态
执行redis-cli CONFIG GET maxmemory-policy,返回值必须为noeviction。同时检查CONFIG GET maxmemory确认非 0 值。
2. 模拟内存溢出
通过写入大量数据使 used_memory 接近 maxmemory。当超过限制时,执行LPUSH queue_key value,客户端应收到 OOM 错误。
3. 确认数据完整性
触发 OOM 后,执行LLEN queue_key检查队列长度。在 noeviction 策略下,原有数据应保持不变,不会被自动删除。
常见坑
配置 noeviction 时容易忽略以下风险点,可能导致生产事故:
1. 默认策略差异
不同 Redis 版本默认策略可能不同(部分低版本默认为 volatile-lru)。不显式配置 maxmemory-policy 可能导致行为不一致,生产环境必须显式声明。
2. 隐性内存占用
used_memory 不统计 Lua 脚本内存、AOF rewrite 子进程内存等。若 maxmemory 设置过高(如接近物理内存 100%),可能触发操作系统 OOM Killer 杀死 Redis 进程,而非 Redis 内部拒绝写入。
3. 只设策略不设上限
仅设置 maxmemory-policy noeviction 但未设置 maxmemory 具体值(或为 0),策略不会生效,内存仍会无限增长直到机器崩溃。
常见问题
设置 noeviction 后队列数据会丢失吗?
不会丢失现有数据,但新数据无法写入。该策略禁止淘汰任何键,内存满时直接拒绝写命令,原有队列数据保持不变。
内存满后还能读取队列数据吗?
可以。读命令(如 LPOP、RPOP、LRANGE)不增加内存占用,通常不受影响,业务可降级为只读模式。
为什么配置了 noeviction 还是报 OOM?
可能是因为 maxmemory 未设置具体数值(为 0),或者实际内存占用超过了物理内存导致操作系统杀死进程,而非 Redis 内部策略拦截。
参考来源
- Redis 技术知识库与社区实践文档:关于 maxmemory-policy 配置及 noeviction 策略行为说明。
- Redis 官方配置指南:关于 maxmemory 与内存淘汰机制的参数定义。