分布式锁的实现-3种常见方式

分布式锁的实现核心思路:找一个公共区来生产和存放锁。

Because:既然是分布式,在单机上创建的实例对象(包括锁对象),也只能作用于本机上,无法保证分布式中多台服务器的一致性,所以此时的锁一定要放在一个公共的区域去创建,各个分布式服务都去访问这个公共区域。 

最常见的公共区域有:数据库,redis和zookepper。具体分析如下:

一:数据库

方法1:

1:在数据库中创建一张存储分布式锁的表,例如:lock_record. 主要的两个字段:第一个主键id,第二个锁名lock_name(唯一类型)

2:在程序中实现上锁的时候,先去创建这个锁。如果创建失败,说明此锁已经存在(因为lock_name是唯一的),被占用,其他的请求阻塞等待。

3:如果创建成功,拿到锁了,就可以执行请求。待执行完毕,释放锁(删除此条记录),其他请求可以重复2和3操作。

缺点:

1:访问数据库成为了瓶颈,效率较低。

2:如果处理请求中出现异常,不能释放锁,其他请求一直进不来,所以在程序中需要设计一个超时处理,超时了,进行锁的释放(删除数据库中此条记录)。

方法2:悲观锁

利用select … where … for update 排他锁

注意: 其他附加功能与实现一基本一致,这里需要注意的是“where name=lock ”,name字段必须要走索引,否则会锁表。有些情况下,比如表不大,mysql优化器会不走这个索引,导致锁表问题。

方法3:乐观锁

所谓乐观锁与前边最大区别在于基于CAS思想,是不具有互斥性,不会产生锁等待而消耗资源,操作过程中认为不存在并发冲突,只有update version失败后才能觉察到。我们的抢购、秒杀就是用了这种实现以防止超卖。
通过增加递增的版本号字段实现乐观锁

2:redis

核心思路:

上锁:通过setnx指令设置锁值(设置成功返回1,失败返回0);

防止死锁:通过expire指令设置过期时间(很重要,防止程序处理异常,不能释放锁);

释放锁:通过delete指令删除key,拿到锁的请求执行完之后要释放锁,让其他请求能拿到锁。

But:有个严重的问题,你知道? 集群下,redis主节点突然挂了,怎么办?

          主节点驾崩了,还没有还得及交出玉玺(锁),此时诸侯(从节点)已经上位直接拿了玉玺。就导致玉玺被两人所持有,不安全产生了。

         为了解决上述问题:redis官方推出redisson高性能的分布式锁实现。

3:zookepper

核心思想:

1:创建“有序临时节点+watch监听”

2:每个请求(线程)都会在规定根节点下创建一个临时节点,创建完毕后,获取所有的节点进行排序,比较自己是不是最小的节点。

3:如果是最小的节点,拿到锁,执行请求,最后释放锁(删除自己创建的临时节点)。

4:如果不是最小的节点,会监听前一个节点,当它的前一个节点释放锁时,他会获得锁。 依次类推!

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

17奋斗8

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值