1.如何实现redis分布式锁?

参考:https://www.cnblogs.com/williamjie/p/9395659.html

参考:https://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653194065&idx=1&sn=1baa162e40d48ce9b44ea5c4b2c71ad7&chksm=8c99f58bbbee7c9d5b5725da5ee38fe0f89d7a816f3414806785aea0fe5ae766769600d3e982&scene=21#wechat_redirect

加锁的正确操作:

jedis.set(lockKey, requestId, NX, PX, expireTime);

一共五个参数:

第一个为key,我们使用key来当锁,因为key是唯一的。

第二个为value,解锁的时候用来判断是不是自己的锁,是自己的就解锁,不是自己的就不解锁。

第三个为NX,当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;

第四个为PX,意思是我们要给这个key加一个过期的设置,具体时间由第五个参数决定。

第五个为time,与第四个参数相呼应,代表key的过期时间。

常见错误:

(1)使用jedis.setnx()jedis.expire()组合实现加锁,不具有原子性,如果程序在执行完setnx()之后突然崩溃,导致锁没有设置过期时间。那么将会发生死锁。

解锁的正确操作:

String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

这里是用了一段lua代码来保证原子性。

常见错误:

判断是否是自己的锁,是的话就解锁

if (requestId.equals(jedis.get(lockKey))) { // 若在此时,这把锁突然不是这个客户端的,则会误解锁 jedis.del(lockKey); }

它是不具备原子性的

2.如何实现zookeeper分布式锁?

参考:https://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653194140&idx=1&sn=07b65a50798c26ecdc0fc555128ab937&chksm=8c99f546bbee7c50b1642dc971cb1f5e244dce661546e141734797c8c23c6c3ad779dfb57d3b&scene=21#wechat_redirect

首先明确一个概念,临时顺序节点

在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号;当创建节点的客户端与zookeeper断开连接后,临时节点会被删除。

获取锁

 

首先,在Zookeeper当中创建一个持久节点ParentLock。当第一个客户端想要获得锁时,需要在ParentLock这个节点下面创建一个临时顺序节点 Lock1。

 

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

 

 

之后,Client1查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock1是不是顺序最靠前的一个。如果是第一个节点,则成功获得锁。

 

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

 

 

这时候,如果再有一个客户端 Client2 前来获取锁,则在ParentLock下载再创建一个临时顺序节点Lock2。

 

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

 

 

Client2查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock2是不是顺序最靠前的一个,结果发现节点Lock2并不是最小的。

 

于是,Client2向排序仅比它靠前的节点Lock1注册Watcher,用于监听Lock1节点是否存在。这意味着Client2抢锁失败,进入了等待状态。

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

 

 

这时候,如果又有一个客户端Client3前来获取锁,则在ParentLock下载再创建一个临时顺序节点Lock3。

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

 

 

 

Client3查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock3是不是顺序最靠前的一个,结果同样发现节点Lock3并不是最小的。

 

于是,Client3向排序仅比它靠前的节点Lock2注册Watcher,用于监听Lock2节点是否存在。这意味着Client3同样抢锁失败,进入了等待状态。

 

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

释放锁

 

释放锁分为两种情况:

 

1.任务完成,客户端显示释放

 

当任务完成时,Client1会显示调用删除节点Lock1的指令。

 

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

 

 

2.任务执行过程中,客户端崩溃

 

获得锁的Client1在任务执行过程中,如果Duang的一声崩溃,则会断开与Zookeeper服务端的链接。根据临时节点的特性,相关联的节点Lock1会随之自动删除。

 

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

 

 

由于Client2一直监听着Lock1的存在状态,当Lock1节点被删除,Client2会立刻收到通知。这时候Client2会再次查询ParentLock下面的所有节点,确认自己创建的节点Lock2是不是目前最小的节点。如果是最小,则Client2顺理成章获得了锁。

 

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

 

 

同理,如果Client2也因为任务完成或者节点崩溃而删除了节点Lock2,那么Client3就会接到通知。

 

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

 

 

最终,Client3成功得到了锁。

 

 

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

3.Zookeeper和Redis分布式锁的优缺点?

java面经查缺补漏之四十一天(今天学redis实现分布式锁)

 

 

相关文章:

  • 2022-01-05
  • 2022-01-17
  • 2021-10-14
  • 2021-09-30
  • 2021-10-01
  • 2021-05-10
  • 2021-05-29
猜你喜欢
  • 2021-10-25
  • 2021-12-20
  • 2022-01-06
  • 2021-08-26
  • 2021-09-26
  • 2021-07-01
相关资源
相似解决方案