为何基于操作的CRDT仅需交换性而非结合性即可保证收敛?
基于操作的CRDT(op-based CRDTs)领域的研究指出,在底层为可靠因果广播通道的前提下,确保收敛(强最终一致性,Strong Eventual Consistency)的充分条件是所有操作具备交换性。但我始终无法理解:为什么此处不需要结合性?即便操作两两可交换,多并发操作场景下结合性似乎仍是不可或缺的属性。
问题示例:存在优先级循环的寄存器CRDT
假设有一个基于操作的寄存器,包含三个操作:
- Op1:将寄存器设为5
- Op2:将寄存器设为10
- Op3:将寄存器设为20
我尝试为这个简易寄存器定义并发事件的仲裁逻辑,看似能构成有效的基于操作的CRDT,仲裁规则如下表:
| Op1 | Op2 | Op3 | |
|---|---|---|---|
| Op1 | LWW | op1 wins | op3 wins |
| Op2 | op1 wins | LWW | op2 wins |
| Op3 | op3 wins | op2 wins | LWW |
注:表中LWW指经典的最后写入者获胜策略,可通过Lamport时钟搭配UUID实现全局唯一全序。
按上表定义的优先级,任意两个操作都是可交换的:比如先执行Op1再执行Op2,和先执行Op2再执行Op1,最终结果都是Op1获胜;其他两两组合同理。
并发场景下的不收敛问题
假设三个节点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
- 节点B:先执行Op2得到值10,再执行Op1得到5,最后执行Op3得到20
- 节点C:先执行Op3得到值20,再执行Op2得到10,最后执行Op1得到5
最终三个节点的状态完全不一致:节点A为10,节点B为20,节点C为5,显然未实现收敛。
核心矛盾分析
问题的根源在于,虽然操作两两可交换,但结合性不成立。以节点A的执行为例:
- 按顺序执行的结果等价于
(Op1·Op3)·Op2,根据仲裁规则,Op1·Op3结果是Op3,再执行Op2后结果是Op2(寄存器值10) - 若调整结合顺序为
Op1·(Op3·Op2),Op3·Op2结果是Op2,再执行Op1后结果是Op1(寄存器值5)
两种结合方式得到的结果完全不同,本质原因是仲裁优先级存在循环(Op1赢Op2,Op2赢Op3,Op3赢Op1),无法形成全局全序,导致多操作并发时无法收敛。
我的困惑
既然这个例子中操作两两可交换但无法收敛,为什么已有研究表明交换性对基于操作的CRDT来说已足够确保收敛?难道这个例子其实是伪装成操作型的状态型CRDT?
内容的提问来源于stack exchange,提问作者Malaski

