V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
JasonLaw
V2EX  ›  程序员

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

  •  
  •   JasonLaw · 2022-05-28 11:59:14 +08:00 · 2378 次点击
    这是一个创建于 888 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 自动删除的时间短吧?

    第 1 条附言  ·  2022-05-28 22:22:43 +08:00

    在Stack Overflow上找到了一个一模一样的问题😂

    Concerns about zookeeper's lock-recipe - Stack Overflow

    18 条回复    2022-06-09 23:25:36 +08:00
    bigbyto
        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
    cubecube
        2
    cubecube  
       2022-05-28 17:08:29 +08:00
    持有的临时节点被销毁会有通知到 client
    JasonLaw
        3
    JasonLaw  
    OP
       2022-05-28 17:10:45 +08:00 via iPhone
    @bigbyto #1 谢谢,也就是 A 释放的时候会发现,然后做对应的动作?
    JasonLaw
        4
    JasonLaw  
    OP
       2022-05-28 17:12:08 +08:00 via iPhone
    @cubecube #2 关键是出现了 network partition ,通知不到 client 。
    cubecube
        5
    cubecube  
       2022-05-28 17:36:26 +08:00
    @JasonLaw 没心跳,锁就自动释放了呀
    JasonLaw
        6
    JasonLaw  
    OP
       2022-05-28 17:43:04 +08:00 via iPhone
    @cubecube #5 ZooKeeper 会自动删除 ephemeral node ,但是 A 不知道发生了这件事🤐
    microxiaoxiao
        7
    microxiaoxiao  
       2022-05-28 18:19:31 +08:00
    虽然没怎么玩过 zoopeeker, 但是做过一点点集群的东西。基本都是民主选举共识决,连不上集群,肯定剔出决策权了。如果是偶数节点还会出现脑裂或者都失效的情况。
    JasonLaw
        8
    JasonLaw  
    OP
       2022-05-28 22:23:35 +08:00
    @microxiaoxiao #7 这个问题不是关于 leader election 的。
    JasonLaw
        9
    JasonLaw  
    OP
       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
        10
    luoqeng  
       2022-05-28 23:31:53 +08:00   ❤️ 3
    解决不了,记得好像已经证明了没有安全的分布式锁。
    分布式锁在异步系统中是一个根本不安全的概念。
    分布式锁只能在正确性和活跃性二选一。

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

    https://jepsen.io/analyses/etcd-3.4.3
    luoqeng
        11
    luoqeng  
       2022-05-28 23:35:46 +08:00
    你给的那个 stackoverflow 下面还贴了一个 GC 暂停的案例 https://cwiki.apache.org/confluence/display/CURATOR/TN10
    luoqeng
        12
    luoqeng  
       2022-05-28 23:42:04 +08:00   ❤️ 1
    [client 自己需要主动去检查 lock 的有效性] 这是一个异步操作,发生请求检查锁有效,到接收到锁有效返回,这个是有网络延迟的,你接收的锁有效的消息可能是过期的,锁已经超时释放掉了。
    luoqeng
        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.
    JasonLaw
        14
    JasonLaw  
    OP
       2022-05-29 08:21:19 +08:00 via iPhone
    @luoqeng 感谢你的回答,主动去检查的确解决不了问题,我想错了。
    xhinliang
        15
    xhinliang  
       2022-05-29 21:35:08 +08:00
    没法避免。
    DDIA 里说了一个 fencing tokens 的概念,看了之后你会发现如果要实现 fencing token 其实就是 storage 必须做到幂等...
    https://tva1.sinaimg.cn/large/e6c9d24egy1h2plos2lz4j20uq0jcdig.jpg
    sun1993
        16
    sun1993  
       2022-05-30 00:09:42 +08:00
    redis 是不是也无法保证分布式锁的准确性?假如一个线程获得了 redis 的分布式锁后,redis 集群中对应的节点挂了,按理说后续的线程获取锁时会失败,但有一种情况是:那个挂掉的主节点被其从节点替换掉了,从节点的 aof 机制恰好没把那个锁标记同步过来,导致后续线程在节点恢复后获取锁成功,从而导致与第一个线程并发执行分布式锁内代码的问题。。
    JasonLaw
        17
    JasonLaw  
    OP
       2022-05-30 08:29:36 +08:00 via iPhone
    @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
        18
    JasonLaw  
    OP
       2022-06-09 23:25:36 +08:00 via iPhone
    @xhinliang #15 其实 fencing token 也是解决不了 lost update 的 https://v2ex.com/t/809587
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5604 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 06:38 · PVG 14:38 · LAX 23:38 · JFK 02:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.