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

第 5 章 —— Register:当前值与陈旧读取

本章目标: 本章完成后,开发者能够用 Register 表达一个 key 的当前逻辑值,并避免把本地查询误当成集群强一致读取。

学习目标

  1. 掌握 put/get/all/remove/size 的本地契约。
  2. 区分更新同一 key 与创建新 key。
  3. 解释 remove 也需要传播和冲突排序。
  4. 为 route hint 写出陈旧读取策略。

前置条件

案例进度

履约服务从 10.0.0.1 滚动到 10.0.0.2。网关更新同一个 fulfillment-primary,旧节点退役后删除提示。

一个 key 的可见值

Register 的可见值操作

put(v2) 提交一个带 lineage metadata 的新候选值,没有数据库行锁保护的覆盖写语义。单节点立即看到 v2;其他节点通过在线 delta 或后续 repair 追上。

register.put(route("fulfillment-primary", "10.0.0.1:8080"));
register.put(route("fulfillment-primary", "10.0.0.2:8080"));
Optional<RouteHint> current = register.get("fulfillment-primary");
Optional<RouteHint> removed = register.remove("fulfillment-primary");

all()size()get() 都观察当前节点已知状态。它们适合本地路由决策和诊断,不是跨节点快照,也没有读 quorum。

业务侧的陈旧读取策略

网关不能只写「从 Register 读取」。它还要回答:条目缺失时是否回源?连接失败时是否尝试次选地址?多长时间后把 hint 视为过期?如果路由错误会产生不可撤销效果,DSM 就不应独自承担决定。

本案例采用:route hint 失败时重新查询权威服务目录并重试一次;订单提交本身仍由履约服务的事务接口保证幂等。

反例与故障注入

把服务每次健康探测结果写成随机 key,然后调用 all().get(0) 取一个地址。条目会无限增长,顺序也没有业务含义。正确模型是稳定服务 key 对应当前 hint;需要保留历史时,把历史写入可审计系统。

另一个错误是 remove 后立刻断言所有节点都为空。remove 与 put 一样需要传播,并可能遇到并发候选值。

实验

运行双节点 put/remove/反向 put 测试,并记录三个观察点:本地提交、远端 put、远端 remove。

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

实验验收卡

字段 内容
运行命令 上述聚焦 Maven 命令
输入或故障 同一 key 的 put、remove;反向节点写入
可观察结果 对端当前可见值按操作变化;远端 remove 有来源事件
证据等级 E3:双节点受控集成测试
本实验未证明 全局强一致读取、历史查询、事务条件更新

回顾

下一步

第 6 章让 A、B 在分区窗口同时更新同一个 key,解释它们为何需要选出同一个 winner。

证据链接