Redis 分布式锁的实现

举报
微枫 发表于 2022/07/19 12:06:25 2022/07/19
【摘要】 Redis 分布式锁的实现

Redis 分布式锁的实现理解基本概念

分布式锁实现的三个核心要素:

加锁

最简单的方法是使用 setnx 命令。 key 是锁的唯一标识,按业务来决定命名。比如想要给一种商品的 秒杀活动加锁,可以给 key 命名为 “lock_sale_商品ID” 。

当一个线程执行 setnx 返回 1 ,说明 key 原本不存在,该线程成功得到了锁;当一个线程执行 setnx 返回 0 ,说明 key 已经存在,该线程抢锁失败。

解锁

有加锁就得有解锁。当得到锁的线程执行完任务,需要释放锁,以便其他线程可以进入。释放锁的最简 单方式是执行 del 指令。

释放锁之后,其他线程就可以继续执行 setnx 命令来获得锁。

锁超时

锁超时是什么意思呢?如果一个得到锁的线程在执行任务的过程中挂掉,来不及显式地释放锁,这块资 源将会永远被锁住(死锁),别的线程再也别想进来。所以, setnx 的 key 必须设置一个超时时间, 以保证即使没有被显式释放,这把锁也要在一定时间后自动释放。 setnx 不支持超时参数,所以需要额 外的指令 expire 。

存在的问题

setnx 和 expire 的非原子性

当某线程执行 setnx ,成功得到了锁, setnx 刚执行成功,还未来得及执行 expire 指令,节点 1 挂 掉了。

可以使用 set (key, value, time, NX),这样就可以取代 setnx 指令。

del 导致误删

假如某线程成功得到了锁,并且设置的超时时间是 30 秒。某些原因导致线程 A 执行的很慢很慢,过了 30 秒都没执行完,这时候锁过期自动释放,线程 B 得到了锁。随后,线程 A 执行完了任务,线程 A 接 着执行 del 指令来释放锁。但这时候线程 B 还没执行完,线程A实际上 删除的是线程 B 加的锁 。

怎么避免这种情况呢?

可以在 del 释放锁之前做一个判断,验证当前的锁是不是自己加的锁。至于具体的实现,可以在加锁的 时候把当前的线程 ID 当做 value ,并在删除之前验证 key 对应的 value 是不是自己线程的 ID。

上面这种方式是两个独立的操作,不是原子性的。

我们可以让获得锁的线程开启一个守护线程,用来给快要过期的锁“续航”。

当过去了 29 秒,线程 A 还没执行完,这时候守护线程会执行 expire 指令,为这把锁“续命”20 秒。守 护线程从第 29 秒开始执行,每 20 秒执行一次。

当线程 A 执行完任务,会显式关掉守护线程。

如果节点 1 忽然断电,由于线程 A 和守护线程在同一个进程,守护线程也会停下。这把锁到了超时的时 候,没人给它续命,也就自动释放了。

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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