Redis 做分布式锁,四个最常见的失效场景

举报
yd_216394844 发表于 2026/10/31 11:48:38 2026/10/31
【摘要】 用 Redis 做分布式锁,跑通不难,难的是在异常情况下还成立。下面四个场景是线上事故里出现频率最高的。场景一,加锁和过期不是原子的。先 SETNX 再 EXPIRE 两段代码,中间进程挂了,锁永远不会过期,后续请求全部阻塞。正确写法是一条命令:SET lock_key unique_value NX PX 30000NX 保证互斥,PX 兜底过期时间,一条命令原子完成。场景二,释放了别人的...

用 Redis 做分布式锁,跑通不难,难的是在异常情况下还成立。下面四个场景是线上事故里出现频率最高的。

场景一,加锁和过期不是原子的。先 SETNX 再 EXPIRE 两段代码,中间进程挂了,锁永远不会过期,后续请求全部阻塞。正确写法是一条命令:

SET lock_key unique_value NX PX 30000

NX 保证互斥,PX 兜底过期时间,一条命令原子完成。

场景二,释放了别人的锁。业务处理超过过期时间,锁自动释放,另一个线程拿到同名锁,此时第一个线程处理完去 DEL,把别人的锁删了。解法是 value 存唯一标识(UUID 或 requestId),释放时先比对再删。比对和删除必须原子,用 Lua 脚本:

if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end

场景三,锁过期了业务还没做完。过期时间设长了怕死锁,设短了怕提前释放。生产做法是加看门狗:后台线程每隔三分之一过期时间检查锁是否还被自己持有,是就续期。Redisson 的 RLock 内置这个机制,别自己造。

场景四,主从切换丢锁。Redis 主从异步复制,主节点写入锁后没来得及同步就宕机,从节点升主,锁丢了,两个客户端同时觉得自己拿到锁。单实例解决不了,要上 Redlock(多主独立部署,过半成功才算加锁成功),或者改用 etcd、ZooKeeper 这类基于共识的组件。

选型建议:防重复提交这类互斥,单实例 Redis 加过期时间就够了。涉及资金、库存这种强一致要求,不要用 Redis 锁,用数据库行锁或乐观锁版本号。

最后一点容易忽略:锁的粒度要和事务边界一起设计。锁加在方法上、事务提交在方法外,锁释放了事务还没提交,读到的仍然是旧数据。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。