registerInstance主要做两件事:
- 发送心跳包
心跳请求定时任务使用线程池ScheduledThreadPoolExecutor.schedule(),而该方法只会调用一次,定时任务的实现是在每次请求任务只会再调用一次ScheduledThreadPoolExecutor.schedule(), 简单说就是nacos在发送心跳的时候,会调用schedule方法,在schedule要执行的任务中,如果正常发送完心跳,会再次调用schedule方法 。
那为什么不直接调用周期执行的线程池ScheduledThreadPoolExecutor.scheduleAtFixedRate()?可能是由于发送心跳服务发生异常后,定时任务还会继续执行,但是周期执行的线程池遇到报错后也不会重复调用执行的任务 。
线程任务BeatTask的run方法,,每次执行会先判断isStopped,如果是false,说明心跳停止,就不会触发下次执行任务 。如果使用定时任务scheduleAtFixedRate,即使心跳停止还会继续执行任务,造成资源不必要浪费 。
- 注册实例
根据上面流程,查看以下的流程图:

文章插图
服务端服务端就是注册中心,服务注册到注册中心,在https://github.com/alibaba/nacos/releases/tag/2.1.1下载源码部署到本地,方便调式和查看,部署方式详见我的另外一篇文章Nacos 源码环境搭建 。
服务端主要接收两个信息:心跳包和实例信息 。
心跳包客户端向服务请求的路径为/v1/ns/instance/beat,对应的服务端为InstanceController类的beat方法:
@PutMapping("/beat")@Secured(action = ActionTypes.WRITE)public ObjectNode beat(HttpServletRequest request) throws Exception {ObjectNode result = JacksonUtils.createEmptyJsonNode();result.put(SwitchEntry.CLIENT_BEAT_INTERVAL, switchDomain.getClientBeatInterval());String beat = WebUtils.optional(request, "beat", StringUtils.EMPTY);RsInfo clientBeat = null;// 判断是否有心跳,存在心跳就转成RsInfoif (StringUtils.isNotBlank(beat)) {clientBeat = JacksonUtils.toObj(beat, RsInfo.class);}String clusterName = WebUtils.optional(request, CommonParams.CLUSTER_NAME, UtilsAndCommons.DEFAULT_CLUSTER_NAME);String ip = WebUtils.optional(request, "ip", StringUtils.EMPTY);int port = Integer.parseInt(WebUtils.optional(request, "port", "0"));if (clientBeat != null) {if (StringUtils.isNotBlank(clientBeat.getCluster())) {clusterName = clientBeat.getCluster();} else {// fix #2533clientBeat.setCluster(clusterName);}ip = clientBeat.getIp();port = clientBeat.getPort();}String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);NamingUtils.checkServiceNameFormat(serviceName);Loggers.SRV_LOG.debug("[CLIENT-BEAT] full arguments: beat: {}, serviceName: {}, namespaceId: {}", clientBeat,serviceName, namespaceId);// 获取实例信息BeatInfoInstanceBuilder builder = BeatInfoInstanceBuilder.newBuilder();builder.setRequest(request);int resultCode = getInstanceOperator().handleBeat(namespaceId, serviceName, ip, port, clusterName, clientBeat, builder);result.put(CommonParams.CODE, resultCode);// 下次发送心跳包间隔result.put(SwitchEntry.CLIENT_BEAT_INTERVAL,getInstanceOperator().getHeartBeatInterval(namespaceId, serviceName, ip, port, clusterName));result.put(SwitchEntry.LIGHT_BEAT_ENABLED, switchDomain.isLightBeatEnabled());return result;}在handleBeat方法中执行线程任务ClientBeatProcessorV2的run方法,延长lastHeartBeatTime时间 。注册中心会定时查询实例,当前时间 - lastHeartBeatTime > 设置时间(默认15秒),就标记实例为不健康实例 。如果心跳实例不健康,发送通知给订阅方,变更实例 。服务端在15秒没有收到心跳包会将实例设置为不健康,在30秒没有收到心跳包会将临时实例移除掉 。实例注册客户端请求的地址是/nacos/v1/ns/instance,对应的是服务端是在InstanceController类 。找到类上对应的post请求方法上 。
注册流程:
InstanceController#register ——>InstanceOperatorClientImpl#registerInstance ——>ClientOperationServiceProxy#registerInstance ——>EphemeralClientOperationServiceImpl#registerInstance
创建 Service服务注册后,将服务存储在一个双层map集合中:
private final Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 什么是服务器?输入网址会发生哪些事情
- 一手机号可注册两微信账号 品牌聚焦用户需求
- 注册商标有用吗,个人注册商标的条件
- 新泰|餐饮开启“抢人”模式,保洁保安需求量大!“春风送岗”系列就业服务活动启动
- 搜狐推广效果怎么样,搜狐公众号平台注册方法
- 中国无忧创业网怎么样,全新定制开发服务众包门户平台
- 公司纳税标准是什么,注册公司流程及费用
- 注册公司注意什么,成立公司十大注意事项
- 公司注册资本多少有什么关系,注册公司流程及费用
- 服务器是干什么的,服务器价位及使用方法
