ARC 1先看见共享状态第 1–4 章

第 3 章 —— 共享状态的稳定身份

本章目标: 本章完成后,开发者能够定义跨节点可识别、可编码且可演进的 RouteHint

学习目标

  1. 区分 collection locator 与 entry key。
  2. 解释 DsmEntityEntityMetadata 和 codec 的协作。
  3. schemaId 管理线格式兼容边界。
  4. 识别身份漂移与 schema mismatch。

前置条件

案例进度

第 2 章只写入了一个地址。本章为它补上稳定身份:集合是 demo/gateway/route-hints,条目 key 是服务名,实体值才是地址和健康提示。

五层身份

共享状态的稳定身份

public record RouteHint(
        String entryKey,
        EntityMetadata metadata,
        String address)
        implements DsmEntity<RouteHint> {

    @Override
    public RouteHint withMetadata(EntityMetadata next) {
        return new RouteHint(entryKey, next, address);
    }
}

entryKey 是集合内部身份,需要在实体内容变化时保持不变。metadata 保存 lineage、HLC、epoch、fencing token 和可选 expiry 等运行时信息。业务不应自行伪造这些字段来赢得冲突。

集合 locator 由 tenantId/applicationId/collectionId 组成。同名 key 放在不同 locator 下,是两个相互隔离的条目。clusterId/serviceId 属于运行与通信域,不能替代集合 locator;第 17 章会验证这两层隔离。

codec 与 schema 不是装饰

两端需要把相同字节解释成相同实体。recordCodec(RouteHint.class) 提供记录编码,而 schemaId("route-hints/v1") 把线格式意图带入集合契约。若一端把 address 当字符串,另一端悄悄改成完全不同的结构,正确行为是拒绝不兼容数据,而不是猜测转换。

安全演进通常遵循:先发布能读取旧/新格式的版本,再切换写格式,最后清理旧读取路径。仅修改 Java 类名不等于完成分布式 schema 迁移。

反例与故障注入

准备两个同 locator、同 schemaId,但 codec 含义不同的节点。即使注册成功,也可能在远端 decode 时失败。反过来,schema 指纹不一致被拒绝,是保护而不是可用性缺陷:它阻止错误数据进入可见状态。

另一个错误是用随机 UUID 作为每次发布的 entryKey。这样每次健康更新都会新增条目,Register 永远没有机会替换同一个逻辑服务。

实验

检查本章身份卡,并运行固定的 schema mismatch 集成测试:

node --test tests/chapter-assets.test.mjs
cd submodule/dsm
mvn -q -pl dsm-integration-test -am \
  -Dtest=TwoNodeIntegrationTest#schemaFingerPrintMismatchIsRejectedGracefullyBetweenTwoNodes \
  -Dsurefire.failIfNoSpecifiedTests=false test

实验先证明书中 locator/key/schema 卡片完整,再证明两个节点对不兼容 schema 采取显式拒绝。

实验验收卡

字段 内容
运行命令 node --test tests/chapter-assets.test.mjs;聚焦 Maven 命令见上文
输入或故障 同一路由集合上的 schema fingerprint 不匹配
可观察结果 章节资产有效;不兼容复制被拒绝且测试通过
证据等级 E3:双节点受控集成测试
本实验未证明 自动 schema 迁移、跨版本滚动升级和生产数据修复

回顾

下一步

第 4 章连接第二个节点,观察同一个 RouteHint 从本地提交变成远端可见。

证据链接