【发布时间】:2012-12-25 21:13:54
【问题描述】:
在阅读 ZooKeeper 的 recipe for lock 时,我很困惑。似乎这个分布式锁的秘诀不能保证“任何快照都没有两个客户端认为他们持有相同的锁”。但是既然ZooKeeper被广泛采用,如果参考文档中出现这样的错误,早就应该有人指出了,那我误会了什么?
引用the recipe for distributed locks:
锁
全局同步的完全分布式锁,意味着在任何时间快照中,没有两个客户端认为他们持有相同的锁。这些可以使用 ZooKeeper 来实现。和优先队列一样,先定义一个锁节点。
- 使用路径名“locknode/guid-lock-”并设置序列和临时标志调用 create()。
- 在锁定节点上调用 getChildren( ) 而不设置监视标志(这对于避免羊群效应很重要)。
- 如果在步骤 1 中创建的路径名具有最小的序列号后缀,则客户端拥有锁,客户端退出协议。
- 客户端调用exists( ),并在锁定目录中的路径上设置了监视标志,并具有下一个最低序列号。
- 如果 exists( ) 返回 false,则转到第 2 步。否则,请等待上一步的路径名通知,然后再转到第 2 步。
考虑以下情况:
- Client1 成功获取锁(在步骤 3 中),ZooKeeper 节点为“locknode/guid-lock-0”;
- Client2 创建节点“locknode/guid-lock-1”,获取锁失败,正在观看“locknode/guid-lock-0”;
- 后来,由于某种原因(例如,网络拥塞),Client1 未能按时向 ZooKeeper 集群发送心跳消息,但 Client1 仍在工作,错误地认为它仍然持有锁。
-
但是,ZooKeeper 可能会认为 Client1 的会话超时,然后
- 删除“locknode/guid-lock-0”,
- 向 Client2 发送通知(或者先发送通知?),
- 但无法及时向 Client1 发送“会话超时”通知(例如,由于网络拥塞)。
- Client2 收到通知,转到第 2 步,获取它自己创建的唯一节点“locknode/guid-lock-1”;因此,Client2 假定它持有锁。
- 但同时,Client1 假定它持有锁。
这是一个有效的场景吗?
【问题讨论】:
-
zookeeper-users 邮件列表上的并行讨论:thread.gmane.org/gmane.comp.java.hadoop.zookeeper.user/5065
标签: apache-zookeeper