基于Redis实现分布式锁

除了Redis,其他的组件能不能实现分布式锁?

当然可以,mysql,也能做分布式锁:给一个字段设置唯一索引,并发插入只有一个能成功。

zookeeper也可以:临时顺序节点。

分布式锁,一般会依托第三方组件来实现,而利用Redis实现则是工作中应用最多的一种。

今天,就让我们从最基础的步骤开始,依照分布式锁的特性,层层递进,步步完善,将它优化到最优,让大家完整地了解如何用Redis来实现一个分布式锁。

分布式锁,一般会依托第三方组件来实现,而利用Redis实现则是工作中应用最多的一种。

今天,就让我们从最基础的步骤开始,依照分布式锁的特性,层层递进,步步完善,将它优化到最优,让大家完整地了解如何用Redis来实现一个分布式锁。

最简化版本

首先,当然是搭建一个最简单的实现方式,直接用Redis的setnx命令,这个命令的语法是: setnx key value如果key不存在,则会将key设置为value,并返回1;如果key存在,不会有任务影响,返回0。

基于这个特性,我们就可以用setnx实现加锁的目的:通过setnx加锁,加锁之后其他服务无法加锁,用完之后,再通过delete解锁,深藏功与名。

上个版本,可能会出现死锁问题---》支持过期时间

最简化版本有一个问题:如果获取锁的服务挂掉了,那么锁就一直得不到释放,就像石沉大海,杳无音信。所以,我们需要一个超时来兜底。

Redis中有expire命令,用来设置一个key的超时时间。但是setnx和expire不具备原子性,如果setnx获取锁之后,服务挂掉,依旧是泥牛入海。

很自然,我们会想到,set和expire,有没有原子操作?

当然有,Redis早就考虑到了这种场景,推出了如下执行语句: set key value nx ex secondsnx表示具备setnx特定,ex表示增加了过期时间,最后一个参数就是过期时间的值。

能够支持过期时间,目前这个锁基本上是能用了。

但是存在一个问题:会存在服务A释放掉服务B的锁的可能。

上个版本可能会导致其他线程获取锁---》加上owner

我们来试想一下如下场景:服务A获取了锁,由于业务流程比较长,或者网络延迟、GC卡顿等原因,导致锁过期,而业务还会继续进行。

这时候,业务B已经拿到了锁,准备去执行,这个时候服务A恢复过来并做完了业务,就会释放锁,而B却还在继续执行。

将参与抢锁的客⼾端id设置在value中(setnx key value),释放锁前校验value中存放的id是否是自己。

在真实的分布式场景中,可能存在几十个竞争者,那么上述情况发生概率就很高,导致同一份资源频繁被不同竞争者同时访问,分布式锁也就失去了意义。

基于这个场景,我们可以发现,问题关键在于,竞争者可以释放其他人的锁。那么在异常情况下,就会出现问题,所以我们可以进一步给出解决方案:分布式锁需要满足谁申请谁释放原则,不能释放别人的锁,也就是说,分布式锁,是要有归属的。

检查锁和释放锁不是原子操作---》引入Lua

加入owner后的版本可以称得上是完善了吗?还有没有什么隐患呢?

也不卖关子了,到这一步其实还存在一个小问题,我们完整的流程是竞争者获取锁执行任务,执行完毕后检查锁是不是自己的,最后进行释放。

流程一梳理,你们肯定明白了,执行完毕后,检查锁,再释放,这些操作不是原子化的。可能锁获取时还是自己的,删除时却已经是别人的了。这可怎么办呢?

Redis可没有直接提供这种场景原子化的操作啊。遇事不要慌,仔细想一想,Redis是不是还有个特性,专门整合原子操作,对,就是它——Lua。

Redis+Lua,可以说是专门为解决原子问题而生。

有了Lua的特性,Redis才真正在分布式锁、秒杀等场景,有了用武之地。

其实到了这一步,分布式锁的前三个特性:对称性、安全性、互斥性,就满足了。可以说是一个可用的分布式锁了,能满足大多数场景的需要。

最初的方案可能会发生死锁---》加上过期时间,但可能会让其他线程获取锁---》加上owner,但检查锁和释放锁不是原子操作。---》引入Lua

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值