V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
SachinBeyond
V2EX  ›  问与答

zookeeper 保证数据一致性的问题

  •  
  •   SachinBeyond · 2020-08-29 13:11:23 +08:00 · 1957 次点击
    这是一个创建于 1340 天前的主题,其中的信息可能已经有所发展或是发生改变。

    ( 1 )执行过半写成功并 commit 的数据 ,集群内部会保证所有机器都执行了这个事务,同时 zk 客户端收到 操作成功的提示。这个是一致性状态,包括集群内部一致性, 客户端响应结果与集群内部状态一致。

    ( 2 )如果 leader 执行过半写 但在 commit 之前 宕机了,那么会选举新的 leader,此时选举之后进行数据同步,这个尚未 commit 的事务最终也会在集群内部达到一致性,但是对于客户端来说 这个操作执行失败了。 此时不就出现问题了吗?比如客户端创建一个节点,集群内部显式节点创建成功,但是客户端却收到节点创建失败的结果

    ( 3 )如果 leader 在将事务 A 的提案发送给 FollowA 后宕机了,集群中其他 follow 节点没有收到事务 A 的提案,经过 leader 选举和数据同步之后,事务 A 的提案应该 会在集群中所有节点都执行并提交(这个理解应该没什么问题吧?),但是此时客户端收到了操作失败的响应结果,而集群内部却显式事务执行成功并提交。 这不就出现不一致了吗?

    问题:zk 如何解决 2 和 3 中出现的问题的?

    9 条回复    2020-09-01 18:04:52 +08:00
    a7082633
        1
    a7082633  
       2020-08-29 13:22:30 +08:00
    2:假如你是 zk 的开发者,为什么不自己先写,然后再 commit 呢?这样即使你的 leader 在 commit 之前宕机了,follow 也没有收到 commit,也就是事务执行失败,重新选举,这就满足一致性了吧。
    3:发提议之后宕机,也就是没发 commit,没 commit 那 follow 就不会执行事务啊。(第 3 点你描述的我有点懵)。
    SachinBeyond
        2
    SachinBeyond  
    OP
       2020-08-29 14:13:50 +08:00
    @a7082633

    (2) leader 执行过半写成功收到了 Follow 的响应(注意 leader 收到了过半写成功确认 ack ), 但是在 leader 向 Follow 发出 commit 指令的时候 leader 宕机了。
    这个时候 集群进行 leader 选举。 选举后 集群内部会进行数据同步,这个没有被上一任 leader 提交的事务 会被新 leader 重新发出 事务提案到 所有 follow,然后所有 follow 执行事务并返回响应 ACK 到新 leader, 新 leader 执行 commit,从而实现 将这个事务应用到集群中每一台机器。

    但是因为上一任 leader 宕机, 客户端会收到操作执行失败的结果。
    比如客户端创建一个节点,集群内部显式节点创建成功,但是客户端却收到节点创建失败的结果。

    ------以上是对原问题的 重新描述--------

    你说的“ follow 也没有收到 commit,也就是事务执行失败 ” 这话好像不太正确。

    参考 https://blog.csdn.net/u010627840/article/details/100526648 这里面有下面一段话

    比如 leader 发起提议 P1,并收到半数以上 follower 关于 P1 的 ACK 后,在广播 commit 消息之前宕机了,选举产生的新 leader 之前是 follower,未收到关于 P1 的 commit 消息,内存中是没有 P1 的数据。而 ZAB 协议的设计是需要保证选主后,P1 是需要应用到集群中的。这块的逻辑是通过选主后的数据同步来弥补。

    也就是,follow 没有收到 commit,但是对于集群来说 这个事务 最终也会被集群中的所有节点执行。
    但是对于客户端,因为 leader 宕机导致事务执行失败,
    lance6716
        3
    lance6716  
       2020-08-29 15:54:57 +08:00 via Android
    返回给客户端状态未确定,等着重试去查
    SachinBeyond
        4
    SachinBeyond  
    OP
       2020-08-29 18:06:43 +08:00
    @lance6716 不太理解你说的是什么意思。 我的困惑就是 2,3 两种情况下客户端都是得到 操作未成功的结果。而集群内部实际上经过一段时间同步后 客户端的操作被 保存下来了。 这个后果很严重呀,比如多个应用尝试创建一个节点,应用 A 尝试创建得到失败的结果,但是实际上节点已经被创建了,然后其他应用又因为节点已经存在无法创建成功,从而导致所有应用都不能工作
    liuhan907
        5
    liuhan907  
       2020-08-29 19:52:45 +08:00 via Android
    @SachinBeyond 没有明确得到提交失败的错误的时候,操作应当被视为状态未确定,需要重试,而不是直接判定为失败。
    SachinBeyond
        6
    SachinBeyond  
    OP
       2020-08-30 07:18:36 +08:00 via Android
    @liuhan907
    有点理解,但又觉得你说的有问题。

    你说的前提是客户端没有明确得到提交失败的错误的时候

    而实际,客户端做 zk 写操作,由于 leader 宕机,集群需要重新选举 leader 和做数据同步。这个时候客户端难道不会收到因 leader 宕机导致写操作事务失败的回复吗?
    liuhan907
        7
    liuhan907  
       2020-08-30 11:11:43 +08:00 via Android
    @SachinBeyond 网络错误和提交错误是两回事。发生网络错误的时候一定要重试来确定状态。
    edgar
        8
    edgar  
       2020-08-30 21:26:35 +08:00
    网络失败和请求执行失败是不同的,网络失败时客户端需要不断重试。可以类比 leader 已经在整个集群里让客户端的请求达成一致,但是正在发送回复给客户端时 leader 挂了或者是客户端挂了。
    SachinBeyond
        9
    SachinBeyond  
    OP
       2020-09-01 18:04:52 +08:00
    @liuhan907
    @edgar

    感谢 !
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1996 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 01:21 · PVG 09:21 · LAX 18:21 · JFK 21:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.