redis锁key被volatile-lru等策略误删会导致并发失控,noeviction是唯一安全底线,需配合锁实例隔离与内存预留。

会,而且影响是直接且致命的——锁 key 被提前淘汰,等于锁凭空消失,业务就可能并发失控。
volatile-lru / volatile-ttl 等策略会误删锁 key
Redis 的 volatile-lru、volatile-ttl、volatile-random 这几类策略,只针对「设置了过期时间(TTL)」的 key 做淘汰。而分布式锁几乎都依赖 EX 或 PX 设置 TTL(比如 SET lock:order:123 "8a7b" NX PX 30000),所以锁 key 正好落在这些策略的淘汰范围内。
常见错误现象:
- 锁明明还没过期,却在高内存压力下被 Redis 主动删掉
- 多个服务同时拿到锁,出现库存超卖、重复扣款
- 日志里查不到
DEL操作,但锁行为异常——其实是淘汰机制在后台静默删 key
根本原因:TTL ≠ 安全保障。只要内存不够,Redis 就可能按策略把你的锁 key 当成“可淘汰对象”干掉,哪怕它离过期还差 29 秒。
为什么不能靠 allkeys-lru 或 allkeys-random 代替?
看起来 allkeys-lru 是对所有 key 淘汰,不区分是否带 TTL,似乎更“公平”。但它的问题更隐蔽:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 锁 key 和缓存 key 混在同一 DB,LRU 会把长期不访问的锁(比如低频任务的锁)优先淘汰,而活跃缓存反而留下
-
allkeys-random更不可控——锁 key 有概率被随机抽中删除,故障完全不可预测 - 一旦锁被误删,没有补偿机制,不像业务缓存丢了还能重建
这不是“概率低就没事”,而是“一次误删就出生产事故”。尤其在流量高峰时,内存压力叠加淘汰逻辑,风险陡增。
noeviction 是唯一安全的底线配置
当 Redis 内存满时,noeviction 策略会让写命令直接返回 (error) OOM command not allowed when used memory > 'maxmemory'.,而不是删 key。这对锁来说反而是保护:
- 加锁失败可被捕获并重试或降级,比“加锁成功但实际无效”更容易发现和处理
- 运维能第一时间收到内存告警,而不是等业务出问题才排查
- 必须配合合理的
maxmemory预留(建议锁专用实例预留 20%+ 内存余量)
注意:noeviction 不是万能解药——它要求你主动做容量规划。如果锁 key 本身设计成 BigKey(比如存了 1MB 的线程堆栈信息),再配 noeviction 也扛不住单次写入失败。
锁 key 隔离才是生产级兜底方案
靠策略选型只能降低风险,真正规避淘汰影响,得从部署结构入手:
- 给锁分配独立 Redis 实例,或至少独占一个 DB(如固定用
DB 15),避免和缓存共享内存空间 - 实例配置强制设为
maxmemory-policy noeviction,并在启动脚本里加校验(防止配置被覆盖) - 锁 key 统一加前缀如
lock:,方便监控其内存占用趋势,早于整体内存瓶颈发现异常增长 - 如果必须复用缓存实例,至少把锁 key 的 TTL 设得足够长(比如 10 分钟),并确保
maxmemory预留充足——但这是妥协方案,不推荐
真正容易被忽略的点:很多人以为“锁加了 EX 就万事大吉”,却没检查 Redis 实例当前生效的 maxmemory-policy 是什么。线上跑着 volatile-lru 却在用 Redisson,默认看门狗续期也救不了被后台淘汰的 key。










