假设我有两个分布式进程运行以下代码,该代码使用zookeeper和curator进行共享锁:
public static void main(String[] args) throws Exception {
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", new ExponentialBackoffRetry(500, 2));
client.start();
InterProcessMutex lock = new InterProcessMutex(client, "/12345");
System.out.println("before acquire");
lock.acquire();
System.out.println("lock has been acquired");
//do some things that need to be done in an atomic fashion
lock.release();
System.out.println("after release");
}
“do some things”注释代表多个语句,这些语句一次只能由一个进程完成。例如多次写入各种数据库。
这一切看起来都很好,直到其中一个java进程在获得锁定后失去与zookeeper的连接。
根据文件:
强烈建议您添加ConnectionStateListener和 注意SUSPENDED和LOST状态的变化。如果是SUSPENDED状态 报道你不能确定你仍然持有锁,除非你 随后获得RECONNECTED状态。如果报告了丢失状态 可以肯定你不再持有锁。
如果我理解正确,在获取锁定后的任何时候,我可能会收到一条通知,说明由于网络问题导致锁定已丢失,此时某些其他进程可能已获得锁定。如果确实如此,则无法保证在获取锁定后您是唯一具有锁定的进程。我必须一次只能由一个进程执行的宝贵声明可能与另一个进程交错。
我误解了上述内容吗?如果是这样,请澄清它的含义。如果我没有误解上述内容,如果无法保证独家访问,策展人锁如何有用?
答案 0 :(得分:8)
它是分布式系统的一般规则:网络和其他实例不稳定。如果您的实例失去与ZooKeeper集合的联系,则无法确定锁定节点的状态。这就是获得SUSPENDED连接状态更改的意义。在内部,ZooKeeper已通知Curator与其ZooKeeper实例的连接已丢失。
这就是说,可以安全地假设在你的会话超时之前没有其他实例会获得锁定,所以你所做的有点取决于你。另请注意,LOST连接状态的含义在Curator 3.x中已更改。在Curator 3.x之前,LOST状态仅表示您的重试策略已过期。在3.x中,Curator现在在连接为SUSPENDED时设置内部计时器,LOST连接状态表示会话已过期。因此,对于许多应用程序,您可以安全地忽略SUSPENDED并仅在收到LOST时退出锁定。
所有这一切都放在一边。即使在单个JVM中使用JDK锁,您也必须能够处理线程中断。将Curator应用程序锁定处理SUSPENDED / LOST与语义相同。
希望这会有所帮助(请注意我是Apache Curator的主要作者)