在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 自动删除的时间短吧?
在Stack Overflow上找到了一个一模一样的问题😂
1
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 |
2
cubecube 2022-05-28 17:08:29 +08:00
持有的临时节点被销毁会有通知到 client
|
4
JasonLaw OP @cubecube #2 关键是出现了 network partition ,通知不到 client 。
|
6
JasonLaw OP @cubecube #5 ZooKeeper 会自动删除 ephemeral node ,但是 A 不知道发生了这件事🤐
|
7
microxiaoxiao 2022-05-28 18:19:31 +08:00
虽然没怎么玩过 zoopeeker, 但是做过一点点集群的东西。基本都是民主选举共识决,连不上集群,肯定剔出决策权了。如果是偶数节点还会出现脑裂或者都失效的情况。
|
8
JasonLaw OP @microxiaoxiao #7 这个问题不是关于 leader election 的。
|
9
JasonLaw OP @bigbyto
@cubecube @microxiaoxiao https://stackoverflow.com/questions/14275613/concerns-about-zookeepers-lock-recipe 表达了跟我一模一样的疑惑,说的解决方法其实跟我想的差不多,client 自己需要主动去检查 lock 的有效性,而不是单纯依赖 ZooKeeper 的通知。 |
10
luoqeng 2022-05-28 23:31:53 +08:00 3
解决不了,记得好像已经证明了没有安全的分布式锁。
分布式锁在异步系统中是一个根本不安全的概念。 分布式锁只能在正确性和活跃性二选一。 通俗来讲,如果进程在持有锁时崩溃,为了不造成死锁,会设置锁失效时间。 但是,如果进程实际上并没有死,而只是暂停或无法访问,那么锁失效会导致它被其他进程持有。暂停的进程恢复运行会以为自己还持有锁。 https://jepsen.io/analyses/etcd-3.4.3 |
11
luoqeng 2022-05-28 23:35:46 +08:00
你给的那个 stackoverflow 下面还贴了一个 GC 暂停的案例 https://cwiki.apache.org/confluence/display/CURATOR/TN10
|
12
luoqeng 2022-05-28 23:42:04 +08:00 1
[client 自己需要主动去检查 lock 的有效性] 这是一个异步操作,发生请求检查锁有效,到接收到锁有效返回,这个是有网络延迟的,你接收的锁有效的消息可能是过期的,锁已经超时释放掉了。
|
13
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.
|
15
xhinliang 2022-05-29 21:35:08 +08:00
没法避免。
DDIA 里说了一个 fencing tokens 的概念,看了之后你会发现如果要实现 fencing token 其实就是 storage 必须做到幂等... https://tva1.sinaimg.cn/large/e6c9d24egy1h2plos2lz4j20uq0jcdig.jpg |
16
sun1993 2022-05-30 00:09:42 +08:00
redis 是不是也无法保证分布式锁的准确性?假如一个线程获得了 redis 的分布式锁后,redis 集群中对应的节点挂了,按理说后续的线程获取锁时会失败,但有一种情况是:那个挂掉的主节点被其从节点替换掉了,从节点的 aof 机制恰好没把那个锁标记同步过来,导致后续线程在节点恢复后获取锁成功,从而导致与第一个线程并发执行分布式锁内代码的问题。。
|
17
JasonLaw OP @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 |
18
JasonLaw OP @xhinliang #15 其实 fencing token 也是解决不了 lost update 的 https://v2ex.com/t/809587
|