ZooKeeper分布式锁!
ZooKeeper分布式锁!
月伴飞鱼方案一:
ZK中节点中存放一个标识,线程获得锁时,先检查该标识是否是无锁标识,若是可修改为占用标识,使用完再恢复为无锁标识。
方案二:
使用子节点,每当有线程来请求锁的时候,便在锁的节点下创建一个子节点。
- 子节点类型必须维护一个顺序,对子节点的自增序号进行排序。
默认总是最小的子节点对应的线程获得锁,释放锁时删除对应子节点便可。
死锁风险:
方案一:
要是持有锁的线程发生了意外,释放锁的代码无法执行,锁就无法释放,其他线程就会一直等待锁,相关同步代码便无法执行。
方案二:
可以利用ZK的临时顺序节点来解决这个问题,只要线程发生了异常导致程序中断,就会丢失与ZK的连接,ZK检测到该链接断开。
就会自动删除该链接创建的临时节点,这样就可以达到即使占用锁的线程程序发生意外,也能保证锁正常释放的目的。
避免羊群效应:
把锁请求者按照后缀数字进行排队,后缀数字小的锁请求者先获取锁。
如果所有的锁请求者都
watch
锁持有者,当代表锁请求者的znode
被删除以后,所有的锁请求者都会通知到。
- 但是只有一个锁请求者能拿到锁,这就是羊群效应。
为了避免羊群效应,每个锁请求者
watch
它前面的锁请求者。
每次锁被释放,只会有一个锁请求者 会被通知到。
这样做还让锁的分配具有公平性,锁定的分配遵循先到先得的原则。
用 ZooKeeper 实现分布式锁的算法流程,根节点为 /lock
:
客户端连接 ZooKeeper,并
在/lock
下创建临时有序子节点。
- 第一个客户端对应的子节点为
/lock/lock01/00000001
,第二个为/lock/lock01/00000002
。其他客户端获取
/lock01
下的子节点列表,判断自己创建的子节点是否为当前列表中序号最小的子节点。如果是则认为获得锁,执行业务代码,否则通过 watch 事件监听
/lock01
的子节点变更消息。
- 获得变更通知后重复此步骤直至获得锁。
完成业务流程后,删除对应的子节点,释放分布式锁。