Zookeeper分布式锁
1.获取锁
首先,在Zookeeper当中创建一个持久节点ParentLock
。当第一个客户端想要获得锁时,需要在ParentLock
这个节点下面创建一个临时顺序节点 Lock1
。
之后,Client1
查找ParentLock
下面所有的临时顺序节点并排序,判断自己所创建的节点Lock1
是不是顺序最靠前的一个。如果是第一个节点,则成功获得锁。
这时候,如果再有一个客户端 Client2
前来获取锁,则在ParentLock
下载再创建一个临时顺序节点Lock2
。
Client2
查找ParentLock
下面所有的临时顺序节点并排序,判断自己所创建的节点Lock2
是不是顺序最靠前的一个,结果发现节点Lock2
并不是最小的。
于是,Client2
向排序仅比它靠前的节点Lock1
注册Watcher
,用于监听Lock1
节点是否存在。这意味着Client2
抢锁失败,进入了等待状态。
这时候,如果又有一个客户端Client3
前来获取锁,则在ParentLock
下载再创建一个临时顺序节点Lock3
。
Client3
查找ParentLock
下面所有的临时顺序节点并排序,判断自己所创建的节点Lock3
是不是顺序最靠前的一个,结果同样发现节点Lock3
并不是最小的。
于是,Client3
向排序仅比它靠前的节点Lock2
注册Watcher
,用于监听Lock2
节点是否存在。这意味着Client3
同样抢锁失败,进入了等待状态。
这样一来,Client1
得到了锁,Client2
监听了Lock1
,Client3
监听了Lock2
。这恰恰形成了一个等待队列,很像是Java当中ReentrantLock
所依赖的AQS(AbstractQueuedSynchronizer)
。
2.释放锁
释放锁分为两种情况:
1.任务完成,客户端显示释放
当任务完成时,Client1
会显示调用删除节点Lock1
的指令。
2.任务执行过程中,客户端崩溃
获得锁的Client1
在任务执行过程中,如果Duang的一声崩溃,则会断开与Zookeeper服务端的链接。根据临时节点的特性,相关联的节点Lock1
会随之自动删除。
由于Client2
一直监听着Lock1
的存在状态,当Lock1
节点被删除,Client2
会立刻收到通知。这时候Client2
会再次查询ParentLock
下面的所有节点,确认自己创建的节点Lock2
是不是目前最小的节点。如果是最小,则Client2
顺理成章获得了锁。
同理,如果Client2
也因为任务完成或者节点崩溃而删除了节点Lock2
,那么Cient3
就会接到通知。
最终,Client3
成功得到了锁。
Zookeeper和Redis分布式锁的比较
下面的表格总结了Zookeeper和Redis分布式锁的优缺点: