ARC 2选择正确的一致性语义第 5–9 章

第 6 章 —— Register 的并发写入与确定性收敛

本章目标: 本章完成后,开发者能够解释并发候选值怎样确定性收敛,并验证自定义 resolver 是否满足交换律。

学习目标

  1. 区分墙上时钟、HLC 与 lineage total order。
  2. 说明默认 last-write-wins 的确定性来源。
  3. 写出 resolver 的交换律检查。
  4. 识别「最终同值」不能修复的外部副作用。

前置条件

案例进度

节点 A 把 fulfillment-primary 指向 east,节点 B 同时指向 west。恢复后两端需要选择同一个可见 hint,否则请求会永久分裂。

确定性比“谁更快”重要

并发候选值的确定性裁决

默认 ConflictResolver.lastWriteWins() 使用 RegisterLineageOrder 比较 metadata。排序包含 lineage/HLC 信息,并以稳定节点标识打破平局。正确性取决于所有节点对同一对候选值执行相同 total order,不能依赖某台机器对本地时间的判断。

数学上,至少要满足:

resolve(A, B).winner == resolve(B, A).winner

如果 resolver 按第一个参数优先,A 节点可能保留 east,B 节点可能保留 west。消息重复、顺序交换后仍无法收敛。

自定义 resolver 的安全入口

ConflictResolver.verified(delegate) 会分别用 (local, remote)(remote, local) 调用 resolver,并比较获胜实体及 outcome family。不满足交换律时抛出 CONFLICT_RESOLVER_NOT_COMMUTATIVE,适合测试、预发或受控上线。

这项检查只覆盖实际输入对,也会让 resolver 执行两次,因此不能视为形式化证明。resolver 仍需保持纯、确定且无外部副作用。

反例与故障注入

定义 resolve(local, remote) -> localWins(local)。在两个节点分别以自己值为 local 的情况下,结果永久分裂。再定义一个读取当前时间或随机数的 resolver,即使偶尔交换后同值,也无法对重放保持确定。

并发库存扣减即使最终选出同一个 winner,也已经可能向两个客户返回成功。这再次证明冲突裁决只解决副本可见值,不撤销外部承诺。

实验

运行自定义 resolver 双节点测试:

cd submodule/dsm
mvn -q -pl dsm-integration-test -am \
  -Dtest=TwoNodeIntegrationTest#customConflictResolversConvergeMergedRegisterValuesAcrossTwoNodes \
  -Dsurefire.failIfNoSpecifiedTests=false test

然后阅读本章 resolver-cases.json,对四个候选策略判断是否纯、交换、确定。

实验验收卡

字段 内容
运行命令 上述 Maven 命令;node --test tests/chapter-assets.test.mjs
输入或故障 两端同 key 并发候选值;输入顺序反转
可观察结果 合并结果在两个节点相同;错误策略在资产检查中被标注
证据等级 E3:受控双节点冲突测试
本实验未证明 所有输入域上的形式化正确性、跨资源事务或外部副作用撤销

回顾

下一步

第 7 章转向有限期所有权:分片处理关注谁在限定时间内有权操作,而非哪个候选值更新。

证据链接