持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情
前文回顾
- 上文我们学习了上锁的过程,那么自然的本文就是解锁的文章了。
释放过程
释放锁分为两种情况:正常释放+中途中断
正常释放
- 当我们线程业务处理结束之后,最后业务会调用zookeeper删除对应的节点。
异常中断
-
如果我们线程正在处理业务中突然zookeeper奔溃了。那么犹豫我们节点临时性,那么当服务重启之后节点就丢失了。这个时候就无法保证当前线程的唯一执行的特权了。
-
由于Client2一直监听着Lock1的存在状态,当Lock1节点被删除,Client2会立刻收到通知。这时候Client2会再次查询ParentLock下面的所有节点,确认自己创建的节点Lock2是不是目前最小的节点。如果是最小,则Client2顺理成章获得了锁。
-
同理,如果Client2也因为任务完成或者节点崩溃而删除了节点Lock2,那么Client3就会接到通知。
-
解决不可重入:客户端加锁时将主机和线程信息写入锁中,下一次再来加锁时直接和序列最小的节点对比,如果相同,则加锁成功,锁重入。
-
锁释放时机:由于我们创建的节点是顺序临时节点,当客户端获取锁成功之后突然session会话断开,ZK会自动删除这个临时节点。
-
单点问题:ZK是集群部署的,主要一半以上的机器存活,就可以保证服务可用性。
解决
Zookeeper第三方客户端curator中已经实现了基于Zookeeper的分布式锁。利用curator加锁和解锁的代码如下:
对比
- 综合下来我觉得还是zookeeper比较适合我们的业务场景,能够保证分布式特性也能避免CPU问题。但是在实现上redis锁貌似更加的简单。这里主要看项目场景吧。没必要为了分布式锁单独引入其中的模块。推荐redis或者zookeeper