点击蓝字关注我们
![264db2256ebbb3b5c0cf22f99da49489.gif](https://img-blog.csdnimg.cn/img_convert/264db2256ebbb3b5c0cf22f99da49489.gif)
![264db2256ebbb3b5c0cf22f99da49489.gif](https://img-blog.csdnimg.cn/img_convert/264db2256ebbb3b5c0cf22f99da49489.gif)
一 环境
集群搭建
01.nacos集群环境架构图
nacos的集群环境架构,建议:域名 + VIP模式,这种可读性好,而且换ip方便,是官网的推荐模式![2ef9cb98413c01cf87ce066a1e94c583.png](https://img-blog.csdnimg.cn/img_convert/2ef9cb98413c01cf87ce066a1e94c583.png)
02.集群部署步骤
整体部署过程与单点部署过程基本一致,只是集群模式是多节点的模式而已 可以参照上一篇文章中的单点部署过程 1)安装包地址 https://github.com/alibaba/nacos/releases 2)解压 解压压缩包为nacos,并复制为nacos-1,nacos-2 3)配置application.properties文件 分别进入nacos/conf,nacos-1/conf,nacos-2/conf目录,进行application.properties文件的配置 a 服务端口配置 三个服务端口分别配置为: server.port=8848 server.port=8847 server.port=8846 b 数据库配置 此步骤为可选步骤。nacos默认使用的是内嵌数据库,我们可以通过配置数据库信息,将数据信息存储在我们的mysql数据库中,可以通过在三个服务的配置文件中均添加以下mysql配置来实现 # db mysql spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true db.user=root db.password=123456 而这个nacos_config数据库的建表脚本在该目录下的nacos-mysql.sql文件中 4)配置cluster.conf文件 同样在conf目录下,分别将原有的cluster.conf.example文件重命名为cluster.conf,并分别添加如下配置 #it is ip #example 192.168.31.95:8848 192.168.31.95:8847 192.168.31.95:8846 5)分别启动服务 linux和mac环境中默认启动是以集群方式启动的,因此直接执行启动命令即可。因此分别进入三个服务的bin目录,执行 ./startup.sh 分别启动服务 6)访问页面,查看集群状态 此时访问http://192.168.31.95:8848/nacos,我们可以看到目前的集群列表有三个节点,一个LEADER和两个FOLLOWER![81f657b3952ed94afbcbc286b900d165.png](https://img-blog.csdnimg.cn/img_convert/81f657b3952ed94afbcbc286b900d165.png)
- 配置不同的服务端口
- 配置声明集群的所有节点
- 满足一定的节点个数
二 原理
源码探究
nacos,经常是以集群形式作为日常的开发或生产环境中的注册中心(当然也经常以配置中心的角色出现) 首先作为一个集群环境,nacos的各个节点的服务是如何保持同步的呢? 作为一个注册中心,它的主要作用实际上就是对服务的管理。那么,客户端各个服务的状态发生变化,注册中心又是如何进行感知并做处理的呢? 我们将分别从以下几个方面进行一步步探究 1) 选举过程 2)心跳过程(集群节点之间) 3)实例注册(服务的变化) 4)实例同步01.选举过程
1.1 理论分析 nacos-server的节点分为三类:leader、follower以及candidate Leader:负责Client交互和log复制,同一时刻系统中最多存在1个 Follower:被动响应请求RPC,从不主动发起请求RPC。接收到请求,会转发给leader处理 Candidate:一种临时的角色,只存在于leader的选举阶段 某个节点想要变成leader,那么就发起投票请求,同时自己变成candidate,如果选举成功,则变为candidate,否则退回为follower 具体流程如下图所示:![f581e9b25639a0a6c0ebd800bef0cb43.png](https://img-blog.csdnimg.cn/img_convert/f581e9b25639a0a6c0ebd800bef0cb43.png)
![e29058e6b8a59a7c3bf5575639eaeacf.png](https://img-blog.csdnimg.cn/img_convert/e29058e6b8a59a7c3bf5575639eaeacf.png)
![71f8023c120e087b7c587deadc098050.png](https://img-blog.csdnimg.cn/img_convert/71f8023c120e087b7c587deadc098050.png)
![2944a0ada7cf10015311f7a2aa1799c6.png](https://img-blog.csdnimg.cn/img_convert/2944a0ada7cf10015311f7a2aa1799c6.png)
resetHeartbeatDue()方法则是,重置心跳间隔时间heartbeatDueMs
为5s
![d868ca3a81caaa4ffc86b590da67b51d.png](https://img-blog.csdnimg.cn/img_convert/d868ca3a81caaa4ffc86b590da67b51d.png)
最后,调用sendVote()方法进行真正的选举操作
3)进入sendVote()方法
![739e2d40a0eb3cbd5e424bc4eddb80d3.png](https://img-blog.csdnimg.cn/img_convert/739e2d40a0eb3cbd5e424bc4eddb80d3.png)
a 组合url,发送投票调用投票的接口:/v1/ns/raft/vote
b 获取请求结果
c 调用decideLeader()方法,确定leader4)进入/v1/ns/raft/vote接口a 接收并处理投票请求b 进入receivedVote()方法该方法进行如下处理:
判断所有的集群节点中是否包含这个请求的远程节点,若不包含则抛出异常
判断请求服务的任期是否大于自己,若不大于,则投票给自己
重置leader的任期时间
当请求服务的任期大于自己,则投票给这个服务,并将自己的状态置为follower
5)进入decideLeader()方法
![fbedf84d332c2dae4e5b253e7ec2329e.png](https://img-blog.csdnimg.cn/img_convert/fbedf84d332c2dae4e5b253e7ec2329e.png)
02.心跳过程
我们看到,在RaftCore.init()中,除了注册了选举的定时任务,还通过GlobalExecutor.register(new HeartBeat())注册了心跳定时任务
而需要知道的是,关于心跳检测,是由leader向各个follower节点发送,以表示自己依旧是健康状态,完全可以担任leader 每500ms检查是否还在时间间隔内(5s),若超过5s,某个follower还没有接收到leader的心跳的话,follower就会发起投票,选择自己为leader 1)进入HeartBeat#run()方法![779c6c17c3b500a9af6f45d0f845638b.png](https://img-blog.csdnimg.cn/img_convert/779c6c17c3b500a9af6f45d0f845638b.png)
![476941ccefdceca959708d8ffd6fc037.png](https://img-blog.csdnimg.cn/img_convert/476941ccefdceca959708d8ffd6fc037.png)
![783c11d30f63648dbfd78f0a2b2be06f.png](https://img-blog.csdnimg.cn/img_convert/783c11d30f63648dbfd78f0a2b2be06f.png)
![dc12e7b7ab43d71dd5238159750ad135.png](https://img-blog.csdnimg.cn/img_convert/dc12e7b7ab43d71dd5238159750ad135.png)
![7aa3cb766d58e1f68676e20eb9ede277.png](https://img-blog.csdnimg.cn/img_convert/7aa3cb766d58e1f68676e20eb9ede277.png)
![e426c449f49c106d8a196070cc4f170b.png](https://img-blog.csdnimg.cn/img_convert/e426c449f49c106d8a196070cc4f170b.png)
![4f82f7b8bdabbd46e130510038d52663.png](https://img-blog.csdnimg.cn/img_convert/4f82f7b8bdabbd46e130510038d52663.png)
a 调用RaftStore#write()方法,将Datum序列化为json写到本地缓存中
b 将Datum存放到RaftCore的datums集合中
c 调用
notifier.addTask(datum, Notifier.ApplyAction.CHANGE)
通知对应的RaftListener,删除key对应的旧的Datum
d 重置leaderDue时间
e 更新本地节点的任期term
小结 1
选举和心跳部分的源码处理流程,用一个图表示,你就更清晰啦
03.实例注册过程
当新服务启动,需要注册在nacos-server上,那么此时就需要进行进行服务的注册,进入ServiceManager#registerInstance()方法 1)进入ServiceManager#registerInstance()方法![b423e52ab7a30bfd2e1ebf48028eea3a.png](https://i-blog.csdnimg.cn/blog_migrate/c5623ee6898afd522d0751264a71796d.png)
![2d7499270fc1bd714fd1a5d70d33da9c.png](https://i-blog.csdnimg.cn/blog_migrate/385a900ba23ef158ffba16daa3419b71.png)
![b148d0a2209421da8481aba3102fb17c.png](https://i-blog.csdnimg.cn/blog_migrate/4d5d5c1986e6bbf0e921bb3de3bda1c5.png)
![d4ffa5f22250f6755de219395e2ea133.png](https://i-blog.csdnimg.cn/blog_migrate/84fb5844f5ecd214a3e73678ae987387.png)
![4fa588a1235fc60506b60e60fdbd8519.png](https://i-blog.csdnimg.cn/blog_migrate/bdacdd9d6d24c2b3fd0a40aa6c248da5.png)
![77a46c2d7b68d5d56df35c89416f1fc4.png](https://i-blog.csdnimg.cn/blog_migrate/71f0b7c228833456e344916570fb67b4.png)
![d439b4b3595128d0104ca62177bfb8a1.png](https://i-blog.csdnimg.cn/blog_migrate/7268a083d6f27b1bba4abd5a9a94f84d.png)
![65a3089fec16674ba908435e6bb46b77.png](https://i-blog.csdnimg.cn/blog_migrate/a6947fa706b11227e779f4bb6606036d.png)
04.实例同步过程
Nacos通过Raft发布内容,内容只是存在了Leader节点上,而要实现服务信息的同步,则采用Raft心跳机制实现 在说心跳过程的时候,我们提到了,leader发送心跳请求时,会分为两种情况,有数据和无数据,其中有数据情况下的数据就是我们的需要同步的服务数据 我们来理一下,在注册服务的时候,addInstance() 方法将 instance 添加到了本地缓存中 然后,raft实现数据从leader到follower的数据同步。follower 接收到包之后,通过 onPublish() 方法进行了持久化,但没有将信息更新到本地缓存,更新到本地缓存,这一动作,实际上是通过一个监听器来实现: notifier.addTask(datum.key, ApplyAction.CHANGE) 即:将本次的变动,添加到通知任务中,然后进行后续处理 我们来继续看看,通知任务将如何被处理 1)添加服务变更到tasks队列![aefc595f8516d69d2362a44d8d908ab7.png](https://i-blog.csdnimg.cn/blog_migrate/fd0d95163c091a74f2bd7859dabdcd1c.png)
![7613ed14b41ad673bdae66c016ee6161.png](https://i-blog.csdnimg.cn/blog_migrate/04d59db859054518ed6074786bf0863b.png)
四 总结
总而言之
好了,今天的推送到这里就结束啦,肝源码,真的是一件枯燥的,艰难的,费时的事情。本篇文章,不夸张的说,杰哥我花了一周多的下班时间准备,本来想着最多两天搞定的。。。 不过还好,完成之后,感觉收获也很大,相信这篇文章,也会带给你们更大的收获 进行分条总结一番~ 1 搭建nacos集群环境 2 源码探究 - 选举 3 源码探究 - 心跳 4 源码探究 - 注册 5 源码探究 - 服务同步 本篇文章,通过搭建集群环境,让大家对于nacos的集群环境有了初步的印象。然后通过跟踪源码,针对nacos服务端的 选举 、 心跳 、 服务注册 以及 服务同步 ,分别进行梳理以及步骤说明,并且每个环节结束,都以一张总体源码流程图进行总结。 相信大家对于 nacos作为注册中心的基本机制 有了一定的了解了! 嗯,就这样。每天学习一点,时间会见证你的强大~ 下期预告: Spring Cloud(六):注册中心nacos-站在客户端角度![178bd4b921014e41b76b5599b34ac421.png](https://i-blog.csdnimg.cn/blog_migrate/c1297a34df5d9f99396bafd3b6c0d1a1.jpeg)
往期精彩回顾
![9c99d9c6762c48aaca60d2c640c3445f.png](https://i-blog.csdnimg.cn/blog_migrate/96ac986580f7ddce9ba86b9b9f4c7ea6.jpeg)
![b65a65962577c0fde93e7bf317cac201.gif](https://i-blog.csdnimg.cn/blog_migrate/4d29be3610e34577a817dcb63d2edba0.gif)