
图中用稳定路径定位一份小型资源描述,真实业务数据仍存放在对应系统。
分布式环境里,客户端怎样知道某个资源现在在哪里?一种办法是提前约定一个稳定名字,再让这个名字指向可读取的定位信息。ZooKeeper 的层次化命名空间可以承担这种协调入口,但不能因此把它理解成任意规模的文件系统或万能业务主键库。
路径回答“到哪里找”
自设一个例子:资源描述保存在 /apps/demo/catalog/current。客户端知道这个绝对路径,就能读取节点里保存的小型元信息,例如资源版本和外部存储位置。资源本身更新时,路径可以保持不变,路径对应的数据发生变化。
这与把服务地址硬编码在每个调用方中不同。稳定入口把名字和当前定位信息分离,让更新有一个共同的查找位置。路径的层级也能表达应用、环境或资源类别,避免不同用途的名字互相挤在同一层。
不过,路径中的词语含义来自你的约定。ZooKeeper 不会因为某个节点叫 current,就自动保证里面保存的是业务上最新的有效资源;“当前版本”何时切换、能否回滚,仍需协议定义。
节点数据不是大对象本体
ZooKeeper 适合管理体积较小的协调信息,而不是把大型文档、模型权重或所有业务记录直接装进节点。可以在节点中存储外部资源的引用、版本和必要校验信息,让客户端再到实际存储系统读取本体。
这也产生了跨系统边界。先发布外部资源还是先更新入口,失败后怎样处理残留版本,必须明确。若入口先指向尚未写完的资源,路径读取成功也没有意义。一个合理的发布流程要验证引用的目标已具备可读条件,再切换协调入口。
客户端读到位置之后,还可能遇到资源被撤销或版本不兼容。因此读取一份元数据不是整个业务动作的事务提交,后续仍需核对资源身份与版本,避免把曾经有效的定位信息当成永久保证。

命名、注册和编号不是同一件事
稳定资源名主要解决查找入口;临时注册常与会话生命周期相关;顺序节点还可以在一定范围内生成不同名称。这些构件可以组合,但它们各自的保证不同,不能统称为“自动生成全球唯一且永不失效的ID”。
顺序号有作用范围和计数边界,创建结果未知时还可能发生重试去重问题。一个节点名称即使在当前命名空间里不冲突,也不代表它适合长期充当跨集群、跨恢复周期的业务主键。业务身份应有自己的稳定定义。
对于需要长期存在的资源入口,不能随手采用会话结束就消失的节点类型。相反,若元信息描述的是某个在线实例,会话绑定又可能符合需求。先确定对象生命周期,再选择节点语义,不能只因为某种创建方式方便就套用。
名字相同,还要防止误改
两个发布者都读取了旧版本,再各自更新同一个入口,后写者可能覆盖先写者的决定。节点版本可以用于条件更新:只有仍是预期版本才修改,否则重新读取并处理冲突。这样至少能把无意识覆盖变成显式失败。
但条件更新也不是跨所有外部系统的事务。资源文件、业务数据库和协调节点之间的关系,需要自己的失败恢复策略。不能因为入口更新是原子的,就推导整个资源发布过程天然原子。
ACL 则约束谁能读写哪些节点,路径长得像分层目录,不代表权限会自动递归继承给全部后代。命名层级和授权范围应分别检查,尤其是不同环境或租户共享一套协调服务时。
客户端缓存也要有更新语义
客户端可能缓存定位信息,减少重复读取。但缓存多久有效、收到变化通知后怎样重新读取、断连时是否继续使用旧值,都要围绕资源需求定义。通知只表示需要检查,不应被当成所有中间版本都完整交付的消息流。
答题时可以用一个资源入口贯穿:约定路径,保存小型定位数据,以版本处理更新冲突,以权限控制修改,再为缓存与失效定义规则。这与集群上下线感知或分布式锁题有联系,主轴却是稳定名字与资源定位的关系。
如果同一个路径先后指向两个不同版本,客户端业务请求应该只携带路径,还是还要携带实际读取到的资源版本?为什么?