早期的Nacos一致性协议
早期Nacos版本架构
服务注册和配置管理一致性协议是分开的,没有下沉到Nacos的内核模块作为通用能力演进,服务发现模块一致性协议的实现和服务注册发现模块的逻辑强耦合在一起,并且充斥着服务注册发现的一些概念。这使得Nacos的服务注册发现模块的逻辑变得复杂且难以维护,耦合了一致性协议层的数据状态,难以做到计算存储彻底分离,以及对计算层的无限水平扩容能力也有一定的影响
解决该问题的思路
必然需要对Nacos的一致性协议做抽象以及下Nacos架构沉,使其成为Core模块的能力,彻底让服务注册发现模块只充当计算能力,同时为配置模块去外部数据库存储打下了架构基础
当前的Nacos架构
新架构已经完成了将一致性协议从原先的服务注册发现模块下沉到了内核模块当中,并且尽可能的提供了统一的抽象接口,使得上层的服务注册发现模块以及配置管理模块,不再需要耦合任何一致性语义,解耦抽象分层后,每个模块能快速演进,并且性能和可用性都大幅提升
Nacos是如何做到一致性下沉协议的呢
一致性协议已经被抽象在了consistency的包中,Nacos对于AP、CP的一致性协议接口使用抽象都在里面,并且在实现具体的一致性协议时,采用了插件可插拔的形式,进一步将一致性协议具体实现逻辑和服务注册发现、配置管理两个模块达到解耦的目的
两个计算模块耦合了带状态的接口
仅做完一致性协议抽象是不够的,如果只做到这里,那么服务注册发现以及配置管理,还是需要依赖一致性协议的接口,在两个计算模块中耦合了带状态的接口;并且,虽然做了比较高度的一致性协议抽象,服务模块以及配置模块却依然还是要在自己的代码模块中去显示的处理一致性协议的读写请求逻辑,以及需要自己去实现一个对接一致性协议的存储,这其实是不好的,服务发现以及配置模块,更多应该专注于数据的使用以及计算,而非数据怎么存储、怎么保障数据一致性,数据存储以及多节点一致的问题应该交由存储层来保证。为了进一步降低一致性协议出现在服务注册发现以及配置管理两个模块的频次以及尽可能让一致性协议只在内核模块中感知,Nacos这里又做了另一份工作——数据存储抽象
数据存储抽象
如果利用一致性协议实现一个存储,那么服务模块以及配置模块,就由原来的依赖一致性协议接口转变为了依赖存储接口,而存储接口后面的具体实现,就比一致性协议要丰富得多了,并且服务模块以及配置模块也无需为直接依赖一致性协议而承担多余的编码工作(快照、状态机实现、数据同步)。使得这两个模块可以更加的专注自己的核心逻辑
架构进一步演进-Nacos的计算层与存储层彻底分离
Nacos自研Distro协议
Distro协议是Nacos社区自研的一种AP分布式协议,是面向临时实例设计的一种分布式协议,其保证了在某些Nacos节点宕机后,整个临时实例处理系统依旧可以正常工作。作为一种有状态的中间件应用的内嵌协议,Distro保证了各个Nacos节点对于海量注册请求的统一协调和存储
设计思想
- Nacos每个节点是平等的都可以处理写请求,同时把新数据同步到其他节点
- 每个节点只负责部分数据,定时发送自己负责数据的校验值到其他节点来保持数据一致性
- 每个节点独立处理读请求,及时从本地发出响应
Distro协议工作原理
数据初始化
新加入的Distro节点会进行全量数据拉取 具体操作是轮询所有的Distro节点,通过向其他的机器发送请求拉取全量数据
在全量拉取操作完成之后,Nacos的每台机器上都维护了当前的所有注册上来的非持久化实例数据
数据校验
在Distro集群启动之后,各台机器之间会定期的发送心跳。心跳信息主要为各个机器上的所有数据的元信息(之所以使用元信息,是因为需要保证网络中数据传输的量级维持在一个较低水平)每台机器在固定时间间隔会向其他机器发起一次数据校验请求
一旦在数据校验过程中,某台机器发现其他机器上的数据与本地数据不一致,则会发起一次全量拉取请求,将数据补齐
写操作
对于一个已经启动完成的Distro集群,在一次客户端发起写操作的流程中,当注册非持久化的实例的写请求打到某台Nacos服务器时,Distro集群处理的流程图如下
整个步骤包括几个部分(图中从上到下顺序)
- 前置的Filter拦截请求,并根据请求中包含的IP和port信息计算其所属的Distro责任节点,并将该请求转发到所属的Distro责任节点上
- 责任节点上的Controller将写请求进行解析
- Distro协议定期执行Sync任务,将本机所负责的所有的实例信息同步到其他节点上
读操作
由于每台机器上都存放了全量数据,因此在每一次读操作中,Distro机器会直接从本地拉取数据。快速响应
这种机制保证了Distro协议可以作为一种AP协议,对于读操作都进行及时的响应。在网络分区的情况下,对于所有的读操作也能够正常返回;当网络恢复时,各个Distro节点会把各数据分片的数据进行合并恢复
小结
Distro协议是Nacos对于临时实例数据开发的一致性协议。其数据存储在缓存中,并且会在启动时进行全量数据同步,并定期进行数据校验
在Distro协议的设计思想下,每个Distro节点都可以接收到读写请求。所有的Distro协议的请求场景主要分为三种情况
- 当该节点接收到属于该节点负责的实例的写请求时,直接写入
- 当该节点接收到不属于该节点负责的实例的写请求时,将在集群内部路由,转发给对应的节点,从而完成读写
- 当该节点接收到任何读请求时,都直接在本机查询并返回(因为所有实例都被同步到了每台机器上)
Distro协议作为Nacos的内嵌临时实例一致性协议,保证了在分布式环境下每个节点上面的服务信息的状态都能够及时地通知其他节点,可以维持数十万量级服务实例的存储和一致性
注
本文参考并借鉴<Nacos架构与原理>