noeviction策略下分布式锁设不上,因内存满时所有写命令(如set nx px)直接oom失败;锁key须避volatile淘汰池,推荐allkeys-lfu策略+maxmemory余量+前缀巡检。

noeviction 不会“拦截”分布式锁的 key,但它会让 SET、EXPIRE 等写操作直接失败——一旦触发,锁根本设不上,比被误删更致命。
为什么分布式锁 key 会撞上 noeviction 错误
很多人以为只要没配 volatile-* 策略,锁 key 就安全。但 noeviction 的真实行为是:内存一满,所有写命令(包括 SET lock:order123 "clientA" NX PX 10000)全部返回 (error) OOM command not allowed when used memory > 'maxmemory'。这不是淘汰,是“拒写”。锁获取失败,业务直接降级或超时。
- 常见诱因:缓存雪崩后大量重建 + 分布式锁 key 集中写入,瞬间冲高内存
- 容易被忽略:锁 key 本身虽小,但若搭配大量临时 token、session、验证码等 volatile 数据,
volatile-lru类策略可能误清锁的持有标识(比如用HSET lock:order123 owner clientA expire_at 1716680880这种结构) - 根本矛盾:
noeviction保数据不丢,但不保服务可用;而分布式锁恰恰是服务可用性的关键路径
锁 key 必须避开 volatile 淘汰池
只要给锁 key 设置了 EXPIRE 或用了 PX 参数,它就进了 volatile 淘汰范围。哪怕你全局配的是 allkeys-lru,它也不会被误删;但一旦改成 volatile-lru,它就和其他验证码 key 一起排队等淘汰。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 绝对不要对锁 key 单独调用
EXPIRE命令——它和SETNX非原子,且显式标记为 volatile - 必须用原子命令:如
SET lock:xxx "val" NX PX 30000,这样 key 虽带过期,但生命周期由 Redis 自管,不参与手动 TTL 干预 - 如果业务要求锁长期有效(如后台任务协调),改用
SET lock:xxx "val" NX+ 定期PEXPIRE续期,避免初始 PX 把它钉死在 volatile 池里 - 检查所有锁封装工具(如 Redisson、Lettuce 的 lock 实现),确认其底层是否默认走
PX——多数是,这是合理设计,但你要知道它带来的淘汰面影响
如何验证锁 key 是否真的“免疫”淘汰
不能只看配置,得实测它的实际归属和访问特征。Redis 不会告诉你某个 key 属于哪个淘汰池,得靠组合命令推断:
- 用
SCAN 0 MATCH "lock:*" COUNT 100找出锁 key,再对每个执行TTL keyname:返回-1表示永不过期(不在 volatile 池),-2表示已删或不存在,其他数值说明它带过期时间 - 用
OBJECT FREQ keyname查访问频次:锁 key 在加锁/解锁路径中必然高频访问,如果OBJECT FREQ返回 0 或极低值,说明它可能被 LRU/LFU 采样机制判定为冷数据(尤其在低流量时段) - 监控指标
evicted_keys和expired_keys必须分开展示:前者涨了说明 allkeys-* 策略在起效;后者涨了但锁 key 消失了,大概率是你混用了 volatile 类策略 + 锁 key 被误标
生产环境推荐的最小可行配置
不是选一个策略就完事,而是策略 + 边界控制 + 观测三者绑定:
- 内存上限必设:
CONFIG SET maxmemory 2gb,不设等于裸奔;值要留 15% 余量(比如实际峰值 1.7gb) - 淘汰策略选
allkeys-lfu(Redis 4.0+),它比 LRU 更抗突发冷 key 冲击,且对锁这类偶发但关键的 key 更友好 - 禁用所有 volatile-* 策略:即使你只打算给验证码用
volatile-ttl,也别开——锁 key 和验证码 key 共享一个 Redis 实例时,策略无法按 namespace 隔离 - 锁 key 命名强制带前缀如
lock:svc:order,配合SCAN+TTL脚本每日巡检,比依赖配置更可靠
最常被跳过的动作是:上线新锁逻辑后,忘了同步检查 maxmemory-policy 是否被其他模块覆盖。一次 CONFIG REWRITE 就可能把线上策略刷回默认 noeviction,而错误日志里只报 OOM,没人去翻 config 日志。










