在基于操作的 CRDT 背景下,事实证明,确保收敛(强最终一致性)的充分条件是所有操作都是可交换的。 (假设有一个底层可靠的因果广播通道)
但是我不明白为什么关联性在这里被删除,因为它看起来像是发生多个并发操作时的一个重要属性,即使它们都是成对交换的。
举个例子:
想象一个基于 op 的寄存器,有 3 个操作 Op1、Op2 和 Op3。
op1 例如是操作 set_the_register_to_5 op2 是操作 set_the_register_to_10 op3 是操作 set_the_register_to_20
这将是一个相当虚拟的寄存器,因为仅限制为 3 个值,但如果我们这样定义并发事件的仲裁,那么它看起来将是一个有效的基于操作的 CRDT:
操作1 | Op2 | Op3 | |
---|---|---|---|
操作1 | LWW | op1获胜 | op3获胜 |
Op2 | op1获胜 | LWW | op2获胜 |
Op3 | op3获胜 | op2获胜 | LWW |
这里 LWW 代表经典的 Last-Writer-Wins,由类似的东西提供 一个lamport时钟和一个UUID以确保唯一性(因此是全序)
因此,对于每对操作,我们定义了一个优先级,以便所有操作都成对交换。
现在假设三个站点A、B、C从同一状态开始,分别并发执行操作op1、op2、op3。 由于它们是同时执行的,因此可以在任何站点以任意顺序接收它们。 (即可靠的因果渠道不会订购它们)
例如,每个站点按以下顺序接收操作: 站点 A:Op1.Op3.Op2 站点 B:Op2.Op1.Op3 站点 C:Op3.Op2.Op1
对于站点 A,首先应用 Op1 会得到 5,应用 Op3 会得到 20,最后应用 Op2 会得到值 10。
对于所有网站:
站点 A 最终状态(即寄存器值)等于 10 B站:注册人数为20 站点C:注册为5
这显然不收敛,因为即使操作成对进行,如果从左到右或从右到左评估,每个站点上的结果也会不同。 例如,站点 A 上从左到右:(Op1.Op3).Op2 = Op3.Op2 = Op2 从右到左:Op1.(Op3.Op2) = Op1.Op2 = Op1
这里的根本问题是仲裁顺序不是全序(它包含一个循环)
但是,所有操作仍然成对交换,但最终并未达到收敛。
所以在我看来,关联性也是必需的,但我肯定在这里遗漏了一些东西,因为事实证明,交换性对于基于操作来说就足够了:)
或者也许是因为它是一种伪装成基于操作的基于状态的方法,我现在不知道?
如果有人能帮忙, 感谢您阅读我的文章。
CRDT 操作是根据它们如何作用于状态来定义的。严格来说,将操作本身相乘是没有意义的,除非通过简单的定义“OpA.OpB 是作用于状态的组合函数:首先应用 OpA,然后应用 OpB”。
用代数术语来说,CRDT 操作更像是组操作,而不是组的二元操作。
因此,当您说站点 A 按 Op1.Op3.Op2 的顺序接收操作时,我们需要知道如何将操作 应用于状态,一次一个,按此顺序。最简单的解释是:
这当然会与其他网站的结果不同。为了实现您想要的仲裁规则,状态需要跟踪已经应用了哪些操作,以便它知道在下一个操作到达时执行不同的操作。如果您以这种形式写出明确的状态和操作,您应该会发现操作不再交换。