当前位置: 首页 > 科技观察

揭秘Nacos的AP架构“DistroConsistencyProtocol”

时间:2023-03-21 16:11:48 科技观察

大家好,我是悟空。这次我们要进入Nacos一致性的底层原理。先给大家一张架构图,让大家对Nacos的架构有一个整体的印象。本文将主要讲解一致性模块中的Distro协议。上一篇文章留下两个知识点:①服务实例注册到Nacos节点后,通过UDP推送给所有服务实例。让其他服务实例知道服务列表中的更改。②如何复制数据到其他节点:当前Nacos节点启动1s延时任务,将数据同步到其他Nacos节点。(分区一致性)第二个知识点是Nacos开发的Distro一致性协议的核心功能。首先,这个Distro协议是针对集群环境的。例如下面三个集群节点组成一个集群。服务A和服务B将注册到此集群。Nacos集群节点Nacos集群环境我们知道Nacos支持两种分布式定理:CP(PartitionConsistency)和AP(PartitionAvailability),AP由Nacos开发的Distro协议保证,CP由Nacos由JRaft协议保证.因为注册中心是系统中非常重要的服务,需要尽可能对外提供可用的服务,所以选择AP来保证服务的高可用。另外Nacos还采用了心跳机制来自动完成服务数据补偿的机制,所以说Distro协议是弱一致性的。如果使用CP协议,则需要当前集群中可用节点的一半以上才能工作。问题:Nacos在哪里使用AP和CP?对于临时服务实例,AP用于保证注册中心的可用性,使用Distro协议。对于持久化服务实例,使用CP保证各个节点的强一致性,JRaft协议。(JRaft是Nacos对Raft的改造)对于配置中心,在没有Database作为存储的情况下,Nacos节点间的内存数据是一致的,使用CP。Nacos提供这种模式只是为了方便用户在本地运行,减少对存储的依赖。在生产环境中,一般会使用外部存储组件来保证数据的一致性。对于配置中心,当有Database作为存储时,Nacos持久化后通知其他节点从数据库中拉取数据,保证数据的一致性。另外,它采用了读写分离的架构来保证高可用,所以这里我觉得这里用的AP,欢迎讨论。对于远程多活,通过AP来保证高可用。提示:临时服务实例是我们默认使用的Nacos注册中心模式。客户端注册后,客户端需要定时上报心跳信息来更新服务实例。注册时可以通过传参设置是否为临时实例。持久化服务实例不需要上报心跳信息,除非手动移除实例,否则不会自动移除。如果实例宕机,Nacos只会将客户端标记为不健康。本文将从源码的角度带你深入剖析Distro协议。知识点预览:①Distro的设计思路和六大机制。②Nacos如何向其他节点同步数据。(异步复制机制,本文重点讲解)③Nacos如何保证所有节点的数据一致性。(周期性检查;健康检查机制,下篇文章讲解)④新增Nacos节点,如何拉取数据。(新的节点同步机制)一、Distro的设计思路和六大机制Distro协议是Nacos开发的用于临时实例数据的共识协议。Distro协议是结合Gossip+Eureka协议的优点并进行优化后出现的。Gossip协议的缺陷是什么?由于发送节点的随机选择,难免会向同一个节点重复发送消息,增加了网络传输的压力,给消息节点带来额外的处理负荷。Distro协议优化:每个节点负责一部分数据,然后将数据同步到其他节点,有效减少消息冗余问题。关于临时实例数据:临时数据实际上是存放在内存缓存中,其他节点启动时会进行全量数据同步,然后节点也会周期性的进行数据校验。别被这个协议吓倒了,它其实是阿里自己实现的一套同步逻辑。AP中的P代表网络分区,所以Distro在分布式集群环境中才能真正发挥作用。保证在由多个Nacos节点组成的Nacos集群环境中,当其中一个Nacos宕机时,整个集群仍然可以正常工作。Distro的设计机制:平等机制:Nacos的每个节点都是平等的,可以处理写请求。(上一讲已经重点介绍了?)异步复制机制:Nacos将变化的数据异步复制到其他节点。(??重点解释)健康检查机制:每个节点只存储部分数据,定期检查客户端状态,保持数据一致性。本地读机制:每个节点独立处理读请求并在本地及时发送响应。新的节点同步机制:Nacos启动时,会从其他节点同步数据。路由转发机制:如果客户端发送的写请求属于自己,则进行处理,否则将路由转发给其他节点。(上一讲重点介绍了?)Distro的设计机制2.异步复制机制:写入数据后如何同步到其他节点2.1核心入口核心源码路径:/naming/consistency/ephemeral/distro/DistroConsistencyServiceImpl.java类名称表示是Distro共识协议的接口实现类。当注册请求交给Nacos节点处理时,核心入口方法是put(),如下图所示:上一讲我们已经说过,这里会做几件事情:添加的过程实例信息①将实例信息存储在MemorycacheconcurrentHashMap里面。②向BlockingQueue添加任务。该任务是将最新的实例列表通过UDP推送给所有的客户端(服务实例),让客户端获取到最新的服务实例列表并缓存到本地。③开启1s延时任务,将数据传递给其他Nacos节点。说明:第二件事是Nacos和客户端如何维护数据一致性,第三件事是Nacos集群之间如何维护数据一致性。由于本文重点讲解Nacos的AP原理,所以会重点讲解第三个东西。第二件事会在后续的文章中说明。2.2sync方法的参数说明首先我们看一下distroProtocol.sync(),这个方法中传递了哪些参数:第一个参数是newDistroKey(),传递一个key和一个常量。key:客户端的服务名,示例值如下:com.alibaba.nacos.naming.iplist.ephemeral.public##DEFAULT_GROUP@@nacos.naming.serviceNameINSTANCE_LIST_KEY_PREFIX:为com.alibaba.nacos。命名.iplist。然后将这两个参数组装成一个DistroKey。第二个参数是同步数据的类型,这里是change。第三个参数是同步任务的延迟时间,1s。2.3sync的核心逻辑:添加任务,先上传一张示意图,帮助大家理解。流程图如下。核心逻辑分为以下几个步骤。遍历其他节点获取节点信息。判断地图中是否存在该任务,如果存在则合并该任务。如果不存在,则将其添加到地图中。后台线程遍历地图,获取任务。向地图添加任务的代码时序图如下:sync核心代码时序图第一个类DistroConsistencyServiceImpl,向地图添加实例信息,然后通过UDP推送给客户端。第二类DistroProtocol主要是循环其他节点。第三个类NacosDelayTaskExecuteEngine是核心类,创建一个同步任务到ConcurrentHashMap中。2.4sync的核心逻辑:后台线程先异步拷贝数据。这个核心逻辑极其复杂。我们看的时候要抓住主线,知道几个重点。悟空在画代码逻辑图的时候,心都碎了。为什么Nacos这么复杂?不用仔细看,一头雾水