欢迎访问我的博客,你的支持,是我最大的动力!

基于Redis的分布式锁和基于ZK的分布式锁的原理

Linux 马从东 141℃ 评论
目录:
[显示]

Redisson支持redis单实例、redis哨兵、redis cluster、redis master-slave等各种部署架构
注意,这个库是一个 java 库
官网:https://redisson.org/

redis分布式锁实现原理

KEYS[1]代表的是你加锁的那个Key
ARGV[1]代表的就是锁Key的默认生存时间,默认30秒
ARGV[2]代表的是加锁的客户端的ID,类似这样:8743c9c0-0795-4907-87fd-6c719a6b4586:1  #分号后的1代表加锁的次数  用于可重入锁
只要客户端1加锁成功,就会启动一个watchdog看门狗,这个后台线程,会每隔10秒检查一下,如果客户端1还持有锁Key,就会不断的延长锁Key的生存时间
释放分布式锁,就是每次都对myLock数据结构中的那个加锁次数减1
如果发现加锁次数是0了,说明这个客户端已经不再持有锁了,此时就会用:“del myLock”命令,从Redis里删除这个Key

Redis Cluster,或者是redis master-slave架构的主从异步复制导致的Redis分布式锁的最大缺陷:在Redis Master实例宕机的时候,可能导致多个客户端同时完成加锁

参考文章
对比各类分布式锁缺陷,抓住Redis分布式锁实现命门
其中V3.1的实际代码:
加锁:SET mykey myvalue EX 300
解锁:EVAL "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 mykey myvalue
若返回1 则mykey被删除 解锁成功;若返回0 解锁失败

ZK分布式锁机制

基于Curator框架为例

临时顺序节点,直接在"my_lock"这个锁节点下,创建一个顺序节点,这个顺序节点由ZK内部自行维护的一个节点序号
客户端A创建完一个顺序节点,会查一下"my_lock"这个锁节点下的所有子节点,并且这些子节点是按照序号排序的,这个时候他大概会拿到一个集合
接着客户端A会走一个关键性的判断:这个集合里创建的顺序节点,自己是否排在首位
如果是的话,就可以加锁
# 客户端B进入
前面部署相同
客户端B加锁失败了后,会通过ZK的API对他的顺序节点的上一个顺序节点加一个监听器,监听这个节点是否被删除等变化
# 客户端A释放锁
把自己在ZK里创建的那个顺序节点删除
删除了那个节点之后,ZK会负责通知监听这个节点的监听器,也就是客户端B之前加的那个监听器
此时客户端B的监听器感知到了上一个顺序节点被删除,也就是排在他之前的某个客户端释放了锁
客户端B重新尝试去获取锁
客户端B判断自己居然是集合中的第一个顺序节点,直接完成加锁

用临时顺序节点的另外一个用意就是,如果某个客户端创建临时顺序节点之后,不小心自己宕机了也没关系,ZK感知到那个客户端宕机,会自动删除对应的临时顺序节点,相当于自动释放锁,或者是自动取消自己的排队

 

库存超卖问题是有很多种技术解决方案的,比如悲观锁,分布式锁,乐观锁,队列串行化,Redis原子操作

基于分布式锁串行化处理,不能支持高并发
解决:把数据分成很多个段,每个段是一个单独的锁
不足:对一个数据分段存储;随机挑选一个分段;某个分段中的数据不足了自动切换到下一个分段数据去处理

 

 

转载请注明:轻风博客 » 基于Redis的分布式锁和基于ZK的分布式锁的原理

喜欢 (0)or分享 (0)