Nacos CP 一致性基础规范深度解析:JRaft 协议模型、读写语义与传输鉴权
Nacos CP 一致性基础规范深度解析JRaft 协议模型、读写语义与传输鉴权【免费下载链接】nacosan easy-to-use dynamic service discovery, configuration and service management platform for building AI cloud native applications.项目地址: https://gitcode.com/GitHub_Trending/na/nacos本文是 Nacos 官方 Foundation CP Consistency Spec 的展开式解读系统梳理 Nacos 在 CAP 理论中选择 CP 路径时的整体设计从CPProtocol/RequestProcessor4CP的抽象契约到JRaftProtocol多 Raft group 运行时再到读写语义、Snapshot 恢复、JRaft 传输鉴权与边界规则。读者读完可掌握 Nacos 内置 CP 实现的分层结构、nacos_config、naming_persistent_service_v2、plugin_state等核心 Raft group 的职责划分以及如何在自研领域内正确接入 CP 基础层。1. 定位Nacos 中的 CP 路径AP 与 CP 是 CAP 理论中的两种一致性取舍。在 Nacos 中CP 路径在分区容忍partition tolerance前提下优先保证强顺序提交strongly ordered committed state当 quorum法定多数、leader 或协议 group 不可用时CP 操作可以选择失败或暂时不可用而绝不会接受分叉写入divergent writes。这一原则在 foundation-cp-consistency-spec.md 中被明确为第一条定位。当前仓库内置的 CP 实现是通过JRaftProtocol接入的 JRaftJRaftProtocol.java。Nacos 允许通过 SPI 加载其他CPProtocol实现但仓库内支持的 CP 语义由 Raft/JRaft 定义替换实现时必须保持既有抽象语义。从源码结构看一致性模块consistency与核心实现模块core做了清晰分层consistency模块只定义抽象契约ConsistencyProtocol、CPProtocol、RequestProcessor4CP、ProtocolMetaData、SnapshotOperationcore模块承载 JRaft 具体实现JRaftProtocol、JRaftServer、NacosStateMachine、ProtocolManager等。2. CP 资源规则什么样的状态适合走 CP规范从正反两面给出了 CP 状态的适用边界。适合使用 CP 状态的资源特征由管理面management或服务端控制路径拥有的持久状态必须在客户端消失、服务端重启后继续存在的状态代表运维人员或开发人员意图、且需要覆盖运行时注册的状态在一个逻辑 group 内要求**单一提交顺序single commit order**的写入可以从snapshot 和已提交日志恢复的状态。不适合使用 CP 的状态高频可丢弃的运行时状态只要 AP 最终收敛即可满足应使用 AP 一致性规范。CP 使用方在接入前必须定义清楚 7 项内容Raft group name 与归属write request 的形态与 operation 值read request 的形态与读取可见性确定性的onApply行为snapshot 保存/加载的形态与兼容性用户可见操作对 leader 或 readiness 的要求group 无 leader、无 processor 或无 quorum 时的错误行为。这 7 项定义正是后文 processor 契约、读写语义和 snapshot 规则的源头。3. 协议模型从 ProtocolManager 到 StateMachine共享一致性接口是ConsistencyProtocolCP 通过CPProtocol对其特化。从源码看ConsistencyProtocol.java 定义了一致性协议的完整生命周期init(Config)初始化、addRequestProcessors()注册处理器、protocolMetaData()返回元数据、getData()/aGetData()读、write()/writeAsync()写、memberChange()成员变更、isReady()就绪判断、shutdown()关闭CPProtocol.java 仅在父接口之上增加了一个isLeader(String group)方法用于判断本节点是否为某个 group 的 leader。规范给出的 CP 分层模型如下ProtocolManager - CPProtocol(JRaftProtocol) - RequestProcessor4CP per group - JRaftServer multi-raft group - NacosStateMachine - processor.onApply / processor.onRequest - snapshot operations各层职责在仓库中均有对应实现ProtocolManagerProtocolManager.java以ip:raftPort形式注入 CP member并异步将 member 变化事件传播给 CP 协议JRaftProtocol内部持有JRaftServer多 Raft group 运行时与JRaftMaintainService运维命令addRequestProcessors()直接调用raftServer.createMultiRaftGroup(processors)NacosStateMachineNacosStateMachine.java负责把已提交日志 apply 到领域层最终回调processor.onApply / onRequest。JRaftProtocol.init()中还注册了RaftEvent订阅者JRaftProtocol.java每次 Raft 事件leader 变化、term、group 成员、错误信息到来时都会更新ProtocolMetaData并注入本节点成员信息raftMetaData同时刷新 Raft group 监控指标——这就是规范中protocolMetaData()记录 leader、term、group members 和错误的落地实现。4. Request Processor 契约每个 CP 领域通过注册一个RequestProcessor4CP接入基础层。RequestProcessor4CP.java 是抽象类仅默认返回空的loadSnapshotOperate()列表其余契约由规范约束group()必须返回稳定且唯一的 group name一个 group 在同一个 server runtime 中应只有一个权威 processoronApply(WriteRequest)必须是确定性的不得依赖慢速远端 IO例如不得在 apply 路径上做 RPC 调用onRequest(ReadRequest)必须按照该 group 的读规则返回响应group 需要 snapshot 恢复时loadSnapshotOperate()必须声明 snapshot operationprocessor 必须将未知 operation 作为显式失败处理processor 只能在committed apply 更新本地状态之后按 事件分发与 NotifyCenter 规范发布领域事件。规范刻意强调了职责边界processor 拥有领域语义domain semanticsCP 基础层拥有 group 路由、leader 转发、日志提交、read-index 处理、metadata 与 snapshot 集成。领域代码只需要关心状态如何被 apply而不用关心日志如何被复制。5. JRaft 运行时规则JRaft 被用作多 group 的 CP 运行时核心规则包括每个RequestProcessor4CP创建一个 Raft group见JRaftServer.createMultiRaftGroup写请求提交到 group leader或被转发到当前 leader已提交日志通过NacosStateMachineapplyfollower replay 会 apply 已提交写入但忽略没有 closure 的 follower-local read entry读路径优先尝试 Raft read-index失败时可回退到 leader readprotocolMetaData()记录 leader、term、group members 与错误isReady()表示协议已启动strict mode 下还要求 group 已存在 leadermember 移除通过 Raft peer-change command 处理新增节点启动时自行注册到集群ProtocolManager通过memberChange(SetString)以ip:raftPort形式下发成员列表JRaftProtocol.memberChange()最多重试 5 次 peer 变更。一个容易被误用的点是实现中的超时是运维默认值不是公开 API 保证。例如JRaftProtocol.write()同步等待 10 秒、getData()等待 5 秒这些只是实现层默认值除非领域 API 显式声明领域规范不得把 JRaft 超时值暴露为用户可见的正确性契约。5.1 JRaft 传输鉴权JRaft Transport AuthenticationJRaft 原生 gRPC 是服务端之间的内部传输inner transport。新版 JRaft client 始终通过 gRPCCallCredentials携带配置的 Nacos server identity服务端始终在分发给 JRaft processor 之前通过ServerInterceptor校验。滚动升级采用临时两态迁移COMPATIBLE - ENFORCEDCOMPATIBLE兼容态缺失或错误 credential 会被限频记录但请求继续执行因为旧版本 member 无法携带 credential每个新 member 发布临时能力supportJraftAuthtrue当完整 member 视图中的所有成员都上报该能力后本机自动且不可逆地进入ENFORCED强制态ENFORCED态下缺失或错误 credential 会在 processor 执行前以 gRPCUNAUTHENTICATED拒绝。仓库实现对应 JRaftAuthUpgradeCoordinator.java其中定义了状态文件名jraft-auth-enforced.state与stateENFORCED标记。规范的补充约束状态迁移是**单向monotonic**的member 新增、删除或元数据更新不得使已强制的进程回到兼容态运行态必须先**锁存latch**强制鉴权再写入{nacos.home}/data/jraft-auth-enforced.state状态文件写入失败不得延迟强制鉴权后续定时检查必须持续重试服务端重启发现该文件时必须立即强制鉴权状态文件不包含 server identity 或 member 数据也不是运维回退开关能力发现、兼容放行、状态迁移与状态文件处理由一个独立兼容组件拥有该组件从引入起即标记废弃Javadoc 明确在Nacos 4.0.0删除且不得拥有永久 credential 解析或校验逻辑。进入强制状态后的降级代价是明确警告的向不携带 JRaft credential 的旧版本做混合滚动降级不保证无损或可用。旧 client 无法调用已强制的新 serverleader 选举、复制、ReadIndex、leader 转发、snapshot 与 CLI 操作都可能因 leader 与 quorum 分布而失败。6. 当前 CP 使用方规范以表格形式列出了仓库内当前的 CP groupGroup归属用途nacos_configPersistence 与 Config 内置存储复制内置存储操作并使 Config dump 等待可读的 committed statenaming_persistent_service_v2Naming复制持久实例注册、更新和注销操作naming_service_metadataNaming复制 service metadata 和 cluster metadatanaming_instance_metadataNaming复制运维态 instance metadatanaming_persistent_serviceNaming 运维复制遗留 naming switch/domain 状态plugin_stateCore plugin选择内置 Raft synchronizer 时复制插件状态和运行时配置变化以plugin_state为例代码中的 group 定义可在 PluginStateProcessor.javaGROUP plugin_state与 RaftPluginStateSynchronizer.javaPLUGIN_STATE_GROUP plugin_state中找到对应。新增 CP 使用方必须把 group 加入相关领域规范并定义该 group 提交的资源语义。7. 读写语义7.1 写规则write request 必须包含group、operation 和序列化数据成功表示写入已按该 group processor 契约被接受并 apply失败必须向调用方暴露不能静默重试后仍作为用户可见成功返回当调用层可能重复提交时领域 apply 逻辑必须幂等或受保护写入不得在 committed apply 之前发布事件。plugin_state是一个值得注意的特殊领域Core 插件领域把它作为内置 Raft synchronizer 的可选运行时资源而不是 Spring context 构造的前置条件。standalone 模式以及显式选择自定义PluginStateSynchronizerProvider的集群都不注册该 group。约束包括processor 不得在 bean 构造器中初始化 CP 或注册 groupCore 接受本地插件状态和配置后再异步初始化默认 Raft synchronizer 和 groupCP 初始化或 group 注册失败只记录日志并将集群插件写能力标记为不可用不得导致 Nacos 启动失败依赖该 group 的调用在其不可用期间必须返回明确的服务端错误不得静默按 standalone 写入或切换到其他 synchronizer。7.2 读规则read request 必须包含目标 group 和序列化查询数据group processor 定义是否支持读取以及读取哪类状态read-index 失败时可以回退到 leader read如果领域绕过 CP 从本地 cache 读取必须在领域规范中记录stale-read 容忍度即允许读到多旧的数据、可接受多久的滞后。8. Snapshot 与恢复Snapshot 规则具有可恢复状态的 group 应提供SnapshotOperation接口定义见 SnapshotOperation.javasnapshot 格式与兼容性由领域 processor 拥有snapshot save/load 必须保留重启后重建服务状态所需的数据没有 snapshot operation 的 group 依赖日志 replay 或独立持久化领域规范必须定义 snapshot 恢复如何与本地 cache 和派生索引交互。一个关键实践对 Config 内置存储而言启动阶段会等待 CP metadata 表明数据可读后才继续 dump 恢复。这是建立在 CP 基础能力与持久化与 Dump 规范之上的 Config 持久化规则——它保证了 dump 不会在 committed state 尚未就绪时读到不完整数据。9. 边界规则最后规范以边界规则收束防止 CP 能力被误用CP 一致性是在 group 内的强顺序提交不保证每个接口都通过 CP 读取CP group 拥有committed 领域状态不拥有传输重试、SDK redo 或 AP 运行时状态除非领域规范明确要求 CP 语义不应使用 JRaft group 串行化高频临时状态CP processor 不得重新定义公开 API 字段、资源身份或鉴权规则CP metadata 是运维协议状态可通过授权的 ops API 暴露但不是领域资源身份替换 CP 实现时必须保持本文定义的CPProtocol、RequestProcessor4CP、group、snapshot、metadata 与错误语义只有领域规范已定义本地读取视图和明确写入不可用语义时才允许把可选领域的 group 注册失败与服务端启动隔离该例外不降低内置 Config 存储等关键 CP 领域的 readiness 要求。10. 延伸阅读CP 一致性是 Nacos 基础能力规范体系的一部分建议结合以下文档整体阅读基础能力规范AP 一致性规范持久化与 Dump 规范事件分发与 NotifyCenter 规范集群成员规范Config 规范Config 持久化、Dump 与历史规范Naming 一致性与客户端状态规范鉴权与权限规范对应的核心源码入口抽象契约见 consistency/src/main/java/com/alibaba/nacos/consistencyJRaft 实现见 core/src/main/java/com/alibaba/nacos/core/distributed/raft传输鉴权升级协调器见 JRaftAuthUpgradeCoordinator.java。【免费下载链接】nacosan easy-to-use dynamic service discovery, configuration and service management platform for building AI cloud native applications.项目地址: https://gitcode.com/GitHub_Trending/na/nacos创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考