使用 ZooKeeper 实现的分布式锁如何避免“错误地认为自己还是锁的持有者”?

2022-05-28 11:59:14 +08:00
 JasonLaw

Lecture 9: More Replication, CRAQ - YouTube中,教授使用 ZooKeeper 实现了分布式锁,伪代码如下:

1. create seq "f" - ephem=t
2. list f*
3. if no lower # file, return
4. if exists(next lower #, watch=t)
5.    wait
6. goto 2.

假设 A 获取到了 lock ,然后它跟 ZooKeeper 出现了 network partition ,最后会导致 f1 被删除,然后 B 就会获取到 lock 。

我的疑问是:怎么避免 A 继续认为自己还是获取到 lock 的?是在某个时间范围内没有收到 ZooKeeper 的“你还是占有这个锁”回应吗?那么这个时间范围应该是比 ZooKeeper 自动删除的时间短吧?

2265 次点击
所在节点    程序员
18 条回复
bigbyto
2022-05-28 15:31:57 +08:00
zkclient 和 server 之间需要创建一个 session ,对于 Ephemeral 节点而言,它的生命周期是 session 级,即随着 session 的销毁而销毁。当 A 和 zkserver 之间出现网络问题导致 session expired ,session 就会被销毁; 如果此时 B 创建了一个新的 Ephemeral 节点,那么这个节点的拥有者(ephemeralOwner)就是 B ,A 在执行释放锁操作(delete ephemeral node)时就会报错。

相关术语
ephemeralOwner: The session id of the owner of this znode if the znode is an ephemeral node. If it is not an ephemeral node, it will be zero.

Ephemeral Nodes: ZooKeeper also has the notion of ephemeral nodes. These znodes exists as long as the session that created the znode is active. When the session ends the znode is deleted. Because of this behavior ephemeral znodes are not allowed to have children.

Ref: https://zookeeper.apache.org/doc/r3.8.0/zookeeperProgrammers.html
cubecube
2022-05-28 17:08:29 +08:00
持有的临时节点被销毁会有通知到 client
JasonLaw
2022-05-28 17:10:45 +08:00
@bigbyto #1 谢谢,也就是 A 释放的时候会发现,然后做对应的动作?
JasonLaw
2022-05-28 17:12:08 +08:00
@cubecube #2 关键是出现了 network partition ,通知不到 client 。
cubecube
2022-05-28 17:36:26 +08:00
@JasonLaw 没心跳,锁就自动释放了呀
JasonLaw
2022-05-28 17:43:04 +08:00
@cubecube #5 ZooKeeper 会自动删除 ephemeral node ,但是 A 不知道发生了这件事🤐
microxiaoxiao
2022-05-28 18:19:31 +08:00
虽然没怎么玩过 zoopeeker, 但是做过一点点集群的东西。基本都是民主选举共识决,连不上集群,肯定剔出决策权了。如果是偶数节点还会出现脑裂或者都失效的情况。
JasonLaw
2022-05-28 22:23:35 +08:00
@microxiaoxiao #7 这个问题不是关于 leader election 的。
JasonLaw
2022-05-28 22:33:52 +08:00
@bigbyto
@cubecube
@microxiaoxiao

https://stackoverflow.com/questions/14275613/concerns-about-zookeepers-lock-recipe 表达了跟我一模一样的疑惑,说的解决方法其实跟我想的差不多,client 自己需要主动去检查 lock 的有效性,而不是单纯依赖 ZooKeeper 的通知。
luoqeng
2022-05-28 23:31:53 +08:00
解决不了,记得好像已经证明了没有安全的分布式锁。
分布式锁在异步系统中是一个根本不安全的概念。
分布式锁只能在正确性和活跃性二选一。

通俗来讲,如果进程在持有锁时崩溃,为了不造成死锁,会设置锁失效时间。
但是,如果进程实际上并没有死,而只是暂停或无法访问,那么锁失效会导致它被其他进程持有。暂停的进程恢复运行会以为自己还持有锁。

https://jepsen.io/analyses/etcd-3.4.3
luoqeng
2022-05-28 23:35:46 +08:00
你给的那个 stackoverflow 下面还贴了一个 GC 暂停的案例 https://cwiki.apache.org/confluence/display/CURATOR/TN10
luoqeng
2022-05-28 23:42:04 +08:00
[client 自己需要主动去检查 lock 的有效性] 这是一个异步操作,发生请求检查锁有效,到接收到锁有效返回,这个是有网络延迟的,你接收的锁有效的消息可能是过期的,锁已经超时释放掉了。
luoqeng
2022-05-28 23:45:50 +08:00
at any snapshot in time no two clients think they hold the same lock is based on the following assumptions: bounded network delay, bounded process pauses and bounded clock error.
JasonLaw
2022-05-29 08:21:19 +08:00
@luoqeng 感谢你的回答,主动去检查的确解决不了问题,我想错了。
xhinliang
2022-05-29 21:35:08 +08:00
没法避免。
DDIA 里说了一个 fencing tokens 的概念,看了之后你会发现如果要实现 fencing token 其实就是 storage 必须做到幂等...
https://tva1.sinaimg.cn/large/e6c9d24egy1h2plos2lz4j20uq0jcdig.jpg
sun1993
2022-05-30 00:09:42 +08:00
redis 是不是也无法保证分布式锁的准确性?假如一个线程获得了 redis 的分布式锁后,redis 集群中对应的节点挂了,按理说后续的线程获取锁时会失败,但有一种情况是:那个挂掉的主节点被其从节点替换掉了,从节点的 aof 机制恰好没把那个锁标记同步过来,导致后续线程在节点恢复后获取锁成功,从而导致与第一个线程并发执行分布式锁内代码的问题。。
JasonLaw
2022-05-30 08:29:36 +08:00
@sun1993 #16

https://redis.io/docs/reference/patterns/distributed-locks/#performance-crash-recovery-and-fsync 解答了你的疑惑。

另外你对 Redlock 算法理解错了,根本不存在 leader 和 follower 。https://redis.io/docs/reference/patterns/distributed-locks/#the-redlock-algorithm 说“ In the distributed version of the algorithm we assume we have N Redis masters. Those nodes are totally independent, so we don’t use replication or any other implicit coordination system.”

另外一个有用的链接: https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html
JasonLaw
2022-06-09 23:25:36 +08:00
@xhinliang #15 其实 fencing token 也是解决不了 lost update 的 https://v2ex.com/t/809587

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/855820

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX