一. 背景
Distro 协议是 Nacos 社区自研的一种 AP 分布式协议,是面向临时实例设计的一种分布式协议,其保证了在某些 Nacos 节点宕机后,整个临时实例处理系统依旧可以正常工作。作为一种有状态的中间应用的内嵌协议,Distro 保证了各个 Nacos 节点对于海量注册请求的统一协调与存储。
作为注册中心,P要保证,C 和 A 需要权衡;常见的一致性协议有 paxos, raft, 他们都是强一致性协议 (CP), 然而这里介绍的 Nacos 的 distro 协议是弱一致性协议 (AP), 即最终一致性协议。
二. 设计思想
Distro 协议的主要涉及思想如下:
- Nacos 每个节点是平等的都可以处理写请求,同时把新数据同步到其他节点。
- 每个节点只负责部分数据,定时发送自己负责数据的校验到其他节点来保持数据一致性。
补充说明:服务端节点都存储所有数据,但每个节点只负责一部分服务,在接收到客户端的 “写”(注册,心跳,下线等)请求后,服务端节点判断请求的服务是否为自己负责,如果是,则处理,否则由负责的节点处理。
- 每个节点独立处理读请求,及时从本地发出响应。
下面将介绍Distro 协议工作原理。
2.1 数据初始化
新加入的 Distro 节点会进行全量数据拉取。具体操是轮询所有的 Distro 节点,通过向其他的机器发送请求拉取全量数据。
在全量拉取操作完成之后,Nacos 的每台机器上都维护了当前的所有注册上来的非持久化实例数据。
2.2 数据校验
在 Distro 集群启动之后,各台机器之间会定期的发送心跳。心跳信息主要为各个机器上的所有数据的元信息 (之所以使用元信息,是因为需要保证网络中数据传输的量级维持在一个较低水平)。这种数据校验会以心跳的形式进行,即每台机器在固定时间间隔会向其他机器发起一次数据校验请求。
一旦在数据校验过程中,某台机器发现其他机器上的数据与本地数据不一致,则会发起一次全量拉取请求,将数据补齐。
2.3 写操作
对于一个已经启动完成的 Distro 集群,在一次客户端发起写操作的流程中,当注册非持久化的实例的写请求打到某台 Nacos 服务器时,Distro 集群处理的流程图如下。
整个步骤包括几个部分 (图中从上到下顺序):
- 前置的 Filter 拦截请求,并根据请求中包含的 IP 和 port 信息计算其所属的 Distro 责任节点,并将该请求转发到所属的 Distro 责任节点上。
- 责任节点上的 Controller 将写请求进行解析。
- Distro 协议定期执行 Sync 任务,将本机负责的所有实例信息同步到其他节点上。
2.4 读操作
由于每台机器上都存放了全量数据,因此在每一次读操作中,Distro 机器会直接从本地拉取数据。快速响应。
这种机制保证了 Distro 协议可以作为一种AP 协议,对于读操作都进行及时的响应。在网络分区的情况下,对于所有的读操作也能正常返回;当网络恢复时,各个 Distro 节点会把各数据分片的数据进行合并恢复。
三. 小结
Distro 协议是Nacos 对于临时实例数据开发的一致性协议。其数据存储在缓存中,并且会在启动时进行全量数据同步,并定期进行数据校验。
在 Distro 协议的设计思想下,每个 Distro 节点都可以接收到读写请求。所有的 Distro 协议的请求场景分为三种情况:
- 当该节点接收到属于该节点负责的实例的写请求时,直接写入。
- 当该节点接收到不属于该节点的实例的写请求时,将在集群内部路由,转发给对应的节点,从而完成读写。
- 当该节点接收到任何读请求时,都直接在本机查询并返回 (因为所有实例都被同步到了每台机器上)。
Distro 协议作为 Nacos 的内嵌临时实例⼀致性协议,保证了在分布式环境下每个节点上面的服务信息的状态都能够及时地通知其他节点,可以维持数十万量级服务实例的存储和⼀致性。