noeviction策略下写操作被拒绝是因为内存达maxmemory后硬性拒绝所有写命令,不释放key也不等待,仅允许读操作;读操作不申请新内存,故不受影响。

Redis 内存满时读操作不受影响,是因为淘汰策略只干预写指令(如 SET、HSET、LPUSH),不阻塞读指令(如 GET、HGET、LRANGE)。这是设计使然,不是 bug 或配置遗漏。
为什么只有写操作被拒绝或触发淘汰?
内存耗尽的本质是“无法分配新空间”,而读操作不申请新内存(只访问已有结构),自然无需干预。写操作则不同:插入新 key、扩展 hash 表、追加 list 元素等,都可能触发内存分配。一旦 maxmemory 达到上限,且淘汰策略无法及时腾出足够空间(或策略本身不淘汰),Redis 就必须拒绝该写请求。
-
noeviction策略下,所有写命令直接返回(error) OOM command not allowed when used memory > 'maxmemory' -
allkeys-lru等策略下,Redis 会先尝试淘汰一批 key,再执行写入;若淘汰后仍不足,仍可能拒绝(尤其在高并发写入突增时) - 读操作全程不修改内存布局,也不新增 key/value 占用,所以永远能走通
哪些写操作会被拦截?不只是 SET
容易误以为只有 SET 受限,其实所有可能扩大内存占用的写命令都会被统一管控:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 键值类:
SET、SETEX、PSETEX、SETNX - 结构类:
HSET、HMSET、LPUSH、RPUSH、SADD、ZADD - 删除类:
DEL不受限(它释放内存),但RENAME和MOVE可能受限——因为目标库中 key 已存在时,可能触发覆盖或扩容逻辑 - 注意:
EXPIRE、TTL、PERSIST这类元数据操作不增加内存,也不受限制
volatile-* 策略下,没设过期时间的 key 真的安全吗?
是的,但代价是“挤占空间”。volatile-lru、volatile-ttl 等策略只在设置了 EXPIRE 的 key 中筛选淘汰目标。这意味着:
- 如果你大量使用永久 key(如配置项、基础字典),它们会持续驻留,把内存“钉死”
- 即使总内存已满,Redis 也不会动这些 key,只会反复淘汰那些带 TTL 的缓存,直到它们全清空 —— 此时写入仍可能失败
- 典型陷阱:误配
volatile-lru却忘了给缓存 key 批量加EX,结果所有 key 都变成“不可淘汰”,等效于noeviction
CONFIG SET maxmemory-policy 切换时有无风险?
有,且风险集中体现在“策略切换瞬间”的行为差异:
- 从
noeviction切到allkeys-lfu:切换后首次写入会立即触发淘汰扫描,可能造成毫秒级延迟尖刺(尤其 key 数量 > 百万级) - 从
volatile-ttl切到allkeys-random:不再优先清理快过期的 key,可能导致大量本该自然失效的数据被长期滞留 - 切换不触发即时淘汰,只影响后续写入决策;已存在的内存压力不会自动缓解
- 生产环境建议:在低峰期切换,并用
INFO memory观察mem_fragmentation_ratio和evicted_keys计数变化
真正难处理的不是“读写分离”本身,而是当淘汰策略和业务数据生命周期错配时,你会看到写入失败率缓慢爬升,但监控里 evicted_keys 增长却很平缓——那往往意味着有一批“不该存在”的永久 key 正在 silently 占坑。查 SCAN + TTL 组合才能揪出来。










