1、什么是分布式锁?
1.1、 概念
为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁。
2、分布式锁的实现有哪些?
-
zookeeper:利用 Zookeeper 的顺序临时节点,来实现分布式锁和等待队列。Zookeeper 设计的初衷,就是为了实现分布式锁服务的。
-
Mysql(数据库):利用
Insert
命令,当表中存在数据时,Insert失败,获取不到锁,成功则表明获取到锁; -
Redis:利用 Redis 的
setnx
命令。此命令同样是原子性操作,只有在key
不存在的情况下,才能set
成功。
2.1、 通过 Redis 分布式锁的实现理解基本概念
分布式锁实现的三个核心要素:加锁、解锁、锁超时
1) 加锁
最简单的方法是使用 setnx
命令。key
是锁的唯一标识,按业务来决定命名。比如想要给一种商品的秒杀活动加锁,可以给 key
命名为 “lock_sale_商品ID” 。value设置成 1
,表示库存。
当一个线程执行 setnx
返回 1
,说明 key
原本不存在,该线程成功得到了锁;当一个线程执行 setnx
返回 0
,说明 key
已经存在,该线程抢锁失败。
2)解锁
有加锁就得有解锁。当得到锁的线程执行完任务,需要释放锁,以便其他线程可以进入。释放锁的最简单方式是执行 del
指令。
3)锁超时
如果一个得到锁的线程在执行任务的过程中挂掉,来不及显式地释放锁,这块资源将会永远被锁住(死锁),别的线程再也别想进来。所以,setnx
的 key
必须设置一个超时时间,以保证即使没有被显式释放,这把锁也要在一定时间后自动释放。setnx
不支持超时参数,所以需要额外的指令。
2.2、由此产生的问题的一些思考
情景:首先线程A拿到了锁,但这个时候线程A挂掉了,锁就会一直存在。
情景:
1)由于设置了超时时间,如果线程A,在规定时间内,没有处理完任务,它自动释放了锁,但实际还在占用资源。
2)线程B这个时候去申请锁,申请到了锁,如果执行的是和A不同的任务(如果相同的任务,导致数据异常)。
3)然后A完成了任务,执行删除锁的命令,实际删除的是B的锁。
1)首先解决删除别人的锁的问题
我们可以在删除的时候进行一个判断,看当前持有锁的线程是不是自己,如果是自己再删除
2)解决自动释放问题
可以用一个监听线程,去监听A锁的持续时间,一般当锁的时间不足2/3时,续时
解决方案一:主从模式
主从模式的问题:如果在主库刚拿到锁的时候,挂了,从库顶上,会导致锁丢失。
解决:改用集群
解决方案二:集群
集群模式的问题:因为集群模式要给各个库都发送锁信息,各个库得到锁的时间不同,会导致锁的持续时间不同
解决:启用监听线程
其他分布式锁的也是类似的,做了一个总结图。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KX8zP0F4-1597712518087)(C:\Users\93584\Desktop\面经\锁.png)]
参考:
https://www.jianshu.com/p/a1ebab8ce78a
https://www.bilibili.com/video/BV1dQ4y1A7Nb