【Redis】阿里面试官让我用Zk(Zookeeper)实现分布式锁( 三 )


那怎么释放锁呢?
删除节点咯 , 删了再通知其他的人过来加锁 , 依次类推 。
我们实现一下 , zk加锁的场景 。
【Redis】阿里面试官让我用Zk(Zookeeper)实现分布式锁
本文插图

是不是 , 只有第一个线程能扣减成功 , 其他的都失败了 。
但是你发现问题没有 , 你加了锁了 , 你得释放啊 , 你不释放后面的报错了就不重试了 。
那简单 , 删除锁就释放掉了 , Lock在finally里面unLock , 现在我们在finally删除节点 。
加锁我们知道创建节点就够了 , 但是你得实现一个阻塞的效果呀 , 那咋搞?
死循环 , 递归不断去尝试 , 直到成功 , 一个伪装的阻塞效果 。
怎么知道前面的老哥删除节点了嗯?
监听节点的删除事件
【Redis】阿里面试官让我用Zk(Zookeeper)实现分布式锁
本文插图

【Redis】阿里面试官让我用Zk(Zookeeper)实现分布式锁
本文插图

【Redis】阿里面试官让我用Zk(Zookeeper)实现分布式锁
本文插图

【Redis】阿里面试官让我用Zk(Zookeeper)实现分布式锁
本文插图

但是你发现你这样做的问题没?
是的 , 会出现死锁 。
第一个仔加锁成功了 , 在执行代码的时候 , 机器宕机了 , 那节点是不是就不能删除了?
你要故作沉思 , 自问自答 , 时而看看远方 , 时而看看面试官 , 假装自己什么都不知道 。
哦我想起来了 , 创建临时节点就好了 , 客户端连接一断开 , 别的就可以监听到节点的变化了 。
嗯还不错 , 那你发现还有别的问题没?
好像这种监听机制也不好 。
怎么个不好呢?
你们可以看到 , 监听 , 是所有服务都去监听一个节点的 , 节点的释放也会通知所有的服务器 , 如果是900个服务器呢?
这对服务器是很大的一个挑战 , 一个释放的消息 , 就好像一个牧羊犬进入了羊群 , 大家都四散而开 , 随时可能干掉机器 , 会占用服务资源 , 网络带宽等等 。
这就是羊群效应 。
【Redis】阿里面试官让我用Zk(Zookeeper)实现分布式锁
本文插图

那怎么解决这个问题?
继续故作沉思 , 啊啊啊 , 好难 , 我的脑袋 。。。。
你TM别装了好不好?
好的 , 临时顺序节点 , 可以顺利解决这个问题 。
怎么实现老公你先别往下看 , 先自己想想 。
之前说了全部监听一个节点问题很大 , 那我们就监听我们的前一个节点 , 因为是顺序的 , 很容易找到自己的前后 。
【Redis】阿里面试官让我用Zk(Zookeeper)实现分布式锁
本文插图

和之前监听一个永久节点的区别就在于 , 这里每个节点只监听了自己的前一个节点 , 释放当然也是一个个释放下去 , 就不会出现羊群效应了 。
【Redis】阿里面试官让我用Zk(Zookeeper)实现分布式锁
本文插图

以上所有代码我都会开源到我的https://github.com/AobingJava/Thanos其实上面的还有瑕疵 , 大家可以去拉下来改一下提交pr , 我会看合适的会通过的 。
你说了这么多 , 挺不错的 , 你能说说ZK在分布式锁中实践的一些缺点么?
Zk性能上可能并没有缓存服务那么高 。
因为每次在创建锁和释放锁的过程中 , 都要动态创建、销毁瞬时节点来实现锁功能 。
ZK中创建和删除节点只能通过Leader服务器来执行 , 然后将数据同步到所有的Follower机器上 。 (这里涉及zk集群的知识 , 我就不展开了 , 以后zk章节跟老公们细聊)


推荐阅读