分布式锁的设计

实现方案

一、mysql实现

二、redis

三、zookeeper

以下主要说一下redis的实现方式。

需要实现的功能

1、只有一个线程能获取到锁,获取不到锁的线程可以自旋一定的时间,如果仍获取不到,则返回获取不到锁。

2、为了防止业务挂了,导致锁没有释放,需要给锁加上过期时间。

3、只能解锁自己加的锁,可以通过加锁时传入请求标识实现

4、实现锁的可重入

问题

1、如何保证加锁和设置超时时间的原子性?

(1)使用lua脚本

(2)高级版本的redis,支持setnx时,同时设置超时时间。

2、解锁时,如何防止被其他客户端解锁?

加锁时,传入请求标识,做为value存储到redis,解锁时,传入请求标识,通过和redis的请求标识进行对比,如果一致,则认为是同一个请求,允许解锁,否则不允许解锁。

但注意:判断请求标识和redis中的value是否一致,一致需要做删除。这块需要是原子性(一般使用调用lua脚本实现),否则有可能把其他请求的锁删除了。考虑如下场景:

(1)请求1获取了锁,准备删除锁

(2)锁过期了

(3)请求2获取了锁

(4)请求1删除了锁,这把锁已经变了,不是请求1的,而是请求2的,也就是请求1删除了请求2的锁。

3、如何实现超时时间的续租?

在加锁成功后,启动一个守护线程,当时间到了的时候,去延迟锁的时间,当业务执行完成后,停止线程。

问题(1):如果执行一半时,服务挂了,导致未解锁。

此时,因服务挂了,线程也就自动停止了。

问题(2):如果看门狗线程挂了,如何保证可靠性?

4、如何实现可重入锁

可以使用计数器,进来一次,加1,出去一次,减1

5、高可用锁如何实现?

比如请求1获取到锁,写到了redis的master节点,此时还没来得及同步到slave,master就挂了,而slave此时如果成为了master,此时,请求2进来,从新的master上获得了锁。此场景下,两个请求都得到了锁了,业务执行必然出现问题。

参考:RedLock->redission看门狗的设计

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值