Nacos 实例注册与同步解析
最近打算将部分应用修改为SpringCloud的形式,减少内部各种奇葩域名的出现,在考察 注册中心 时将该代码大致了解了一下,记录一下.
针对临时实例,Nacos版本:1.1.3 最新master分支. 克隆到本地,将
namingpom.xml文件移除maven-assembly-plugin, 包修改为SpringBoot配置
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.1.1.RELEASE</version><configuration><mainClass>com.alibaba.nacos.naming.NamingApp</mainClass><layout>ZIP</layout></configuration><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin>
分别拷贝2份 path/naming/target/nacos-naming-1.1.3.jar到 /Users/admin/Desktop/note 和 /Users/admin/Desktop/task ,分别配置3份 nacos/conf/cluster.conf,内容如下
192.168.63.127:18848192.168.63.127:8848192.168.63.127:8858
最后分别启动这3个实例. 2个jar包启动,1个idea启动
注册流程
执行 curl 注册
curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?port=9112&healthy=true&ip=11.11.11.11&weight=1.0&serviceName=nacos.test.3'
针对 InstanceController 发起 POST 请求
- 服务不存在则创建空的服务
createEmptyService, 原因:Nacos是基于service <---> cluster <---> instance作为模型,所有实例的存在都必须依托于service, 涉及服务的初始化和监听器的启动service初始化,启动ClientBeatCheckTask5s定时任务,用于标记实例不健康以及删除实例,服务集群初始化.- 加入2个监听器,后期实例发生变化触发
onChange操作
- 获取添加后的全部实例,和当前存储的服务数据进行比较对实例进行
add/delete, 此处不涉及数据的更新操作. - 保存服务
- DistroConsistencyServiceImpl#onPut 数据保持到本地,添加一个
change事件到队列,由notifier线程异步执行监听器操作,触发service的checksum计算,更新实例IP信息. - TaskDispatcher#addTask添加一个任务到调度队列中,由
TaskScheduler异步执行发送给其他服务节点。
- DistroConsistencyServiceImpl#onPut 数据保持到本地,添加一个
同步流程
同步流程紧跟上述服务注册.
TaskScheduler#run 将队列中的 key 取出,对其他服务节点发起 PUT 请求 ,地址 [http://127.0.0.1:18848/nacos/v1/ns/distro/datum](http://127.0.0.1:18848/nacos/v1/ns/distro/datum)
public static boolean syncData(byte[] data, String curServer) throws Exception {try {Map<String, String> headers = new HashMap<>(128);HttpClient.HttpResult result = HttpClient.httpPutLarge("http://" + curServer + RunningConfig.getContextPath()+ UtilsAndCommons.NACOS_NAMING_CONTEXT + DATA_ON_SYNC_URL, headers, data);if (HttpURLConnection.HTTP_OK == result.code) {return true;}if (HttpURLConnection.HTTP_NOT_MODIFIED == result.code) {return true;}throw new IOException("failed to req API:" + "http://" + curServer+ RunningConfig.getContextPath()+ UtilsAndCommons.NACOS_NAMING_CONTEXT + DATA_ON_SYNC_URL + ". code:"+ result.code + " msg: " + result.content);} catch (Exception e) {Loggers.SRV_LOG.warn("NamingProxy", e);}return false;}
请求到达 DistroController#onSyncDatum, 其他服务节点收到请求后,进行上述注册流程,省去 TaskDispatcher#addTask 部分,因为该服务不属于这个节点处理,所以不需要进行同步。到此服务注册和同步流程结束
因为都是属于后台异步处理,服务节点达到一致需要一定的时间,但会保证最终的一致.
实例过期
在服务注册中通过创建空的服务初始化了服务的定时任务,该定时任务会执行实例过期和实例删除操作。
标记不健康实例
for (Instance instance : instances) {if (System.currentTimeMillis() - instance.getLastBeat() > instance.getInstanceHeartBeatTimeOut()) {if (!instance.isMarked()) {if (instance.isHealthy()) {instance.setHealthy(false);//实例心跳过期,标记实例不健康,但是不删除实例getPushService().serviceChanged(service);SpringContext.getAppContext().publishEvent(new InstanceHeartbeatTimeoutEvent(this, instance));}}}}
删除监控实例
for (Instance instance : instances) {if (instance.isMarked()) {continue;}if (System.currentTimeMillis() - instance.getLastBeat() > instance.getIpDeleteTimeout()) {deleteIP(instance);//删除实例}}
执行删除实例 ,向自己发起一个 DELETE 的http请求,等同于 客户端 主动调用注销请求
curl -X DELETE 127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.test.1&ip=1.1.1.1&port=8888&clusterName=TEST1
请求到达 InstanceController#deregister , 执行服务移除操作.
- 将服务从缓存中移除,例子如下:缓冲中有数据
1,2,3,4,4过期,可获取到最终数据1,2,3. - 执行
注册流程的第二步保持服务,因为注册和注销本质都是服务变更.
完
2019-08-24
