SpringCloud Nacos 心跳机制和服务健康检查源码解析

1 客户端心跳机制

1.1 客户端注册源码流程

https://blog.csdn.net/qq_34125999/article/details/117566523

1.2 NacosNamingService

1.2.1 注册服务方法

	@Override
    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    	
        NamingUtils.checkInstanceIsLegal(instance);
        //创建group@@servciceName
        String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
        //如果当前实例是临时实例(默认是临时实例)
        if (instance.isEphemeral()) {
	        // 创建心跳信息
            BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
            //beanReactor添加心跳信息
            beatReactor.addBeatInfo(groupedServiceName, beatInfo);
        }
        //发送请求向nacos注册服务
        serverProxy.registerService(groupedServiceName, groupName, instance);
    }

1.3 BeatReactor

1.3.1 buildBeatInfo

  public BeatInfo buildBeatInfo(String groupedServiceName, Instance instance) {
        //创建心跳对象
        BeatInfo beatInfo = new BeatInfo();
        //封装心跳信息
        beatInfo.setServiceName(groupedServiceName);
        beatInfo.setIp(instance.getIp());
        beatInfo.setPort(instance.getPort());
        beatInfo.setCluster(instance.getClusterName());
        beatInfo.setWeight(instance.getWeight());
        beatInfo.setMetadata(instance.getMetadata());
        beatInfo.setScheduled(false);
        /**
         * 心跳间隔默认为5秒
         */
        beatInfo.setPeriod(instance.getInstanceHeartBeatInterval());
        return beatInfo;
    }

在这里插入图片描述

1.3.2 addBeatInfo

在这里插入图片描述

1.3.3 BeatTask

描述: 查看 BeatTask 的run()方法。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3 服务端处理心跳

描述: 查看接口。
在这里插入图片描述
在这里插入图片描述
描述: 异步处理请求。
在这里插入图片描述
****
描述: 查看异步任务ClientBeatProcessor,run方法。

 @Override
    public void run() {
        //找到当前服务
        Service service = this.service;
        if (Loggers.EVT_LOG.isDebugEnabled()) {
            Loggers.EVT_LOG.debug("[CLIENT-BEAT] processing beat: {}", rsInfo.toString());
        }
        //获取相关信息
        String ip = rsInfo.getIp();
        String clusterName = rsInfo.getCluster();
        int port = rsInfo.getPort();
        Cluster cluster = service.getClusterMap().get(clusterName);
        List<Instance> instances = cluster.allIPs(true);
            
        //遍历找到注册心跳的服务
        for (Instance instance : instances) {
            
            //比对ip、port
            if (instance.getIp().equals(ip) && instance.getPort() == port) {
                if (Loggers.EVT_LOG.isDebugEnabled()) {
                    Loggers.EVT_LOG.debug("[CLIENT-BEAT] refresh beat: {}", rsInfo.toString());
                }
                
                /**
                 * 设置心跳
                 */   
                instance.setLastBeat(System.currentTimeMillis());
                
                //如果当前服务没被标记并且不健康,更新当前服务状态
                if (!instance.isMarked()) {
                    if (!instance.isHealthy()) {
                        instance.setHealthy(true);
                        Loggers.EVT_LOG
                                .info("service: {} {POS} {IP-ENABLED} valid: {}:{}@{}, region: {}, msg: client beat ok",
                                        cluster.getService().getName(), ip, port, cluster.getName(),
                                        UtilsAndCommons.LOCALHOST_SITE);
                        getPushService().serviceChanged(service);
                    }
                }
            }
        }
    }

2 服务端健康检查

2.1 服务端注册nacos

https://blog.csdn.net/qq_34125999/article/details/117676950

2.2 Service

描述: 当服务注册时,会执行Service init方法,当前方法会异步开启注册服务健康监测。
在这里插入图片描述

2.3 HealthCheckReactor

描述: scheduleCheck方法,会异步提交ClientBeatCheckTask任务,延迟5秒后执行,并且每隔5秒执行。

 public static void scheduleCheck(ClientBeatCheckTask task) {
        futureMap.putIfAbsent(task.taskKey(), GlobalExecutor.scheduleNamingHealth(task, 5000, 5000, TimeUnit.MILLISECONDS));
    }

2.4 ClientBeatCheckTask

描述: 查看异步执行任务 run方法。

@Override
    public void run() {
        try {
            if (!getDistroMapper().responsible(service.getName())) {
                return;
            }

            if (!getSwitchDomain().isHealthCheckEnabled()) {
                return;
            }
            
            //获取服务所有Instance
            List<Instance> instances = service.allIPs(true);

            // first set health status of instances:
            //第一次,遍历所有服务
            for (Instance instance : instances) {
                //如果当前时间减去服务上次注册时间大于15秒
                if (System.currentTimeMillis() - instance.getLastBeat() > instance.getInstanceHeartBeatTimeOut()) {
                    //如果服务没被标记并且服务是健康的那么设置服务为非健康状态
                    if (!instance.isMarked()) {
                        if (instance.isHealthy()) {
                            instance.setHealthy(false);
                            Loggers.EVT_LOG
                                    .info("{POS} {IP-DISABLED} valid: {}:{}@{}@{}, region: {}, msg: client timeout after {}, last beat: {}",
                                            instance.getIp(), instance.getPort(), instance.getClusterName(),
                                            service.getName(), UtilsAndCommons.LOCALHOST_SITE,
                                            instance.getInstanceHeartBeatTimeOut(), instance.getLastBeat());
                            getPushService().serviceChanged(service);
                            ApplicationUtils.publishEvent(new InstanceHeartbeatTimeoutEvent(this, instance));
                        }
                    }
                }
            }

            if (!getGlobalConfig().isExpireInstance()) {
                return;
            }
            
            //第二次遍历所有服务
            // then remove obsolete instances:
            for (Instance instance : instances) {

                if (instance.isMarked()) {
                    continue;
                }
                //如果当前时间减去服务上次心跳时间大于30秒,那么当前服务
                if (System.currentTimeMillis() - instance.getLastBeat() > instance.getIpDeleteTimeout()) {
                    // delete instance
                    Loggers.SRV_LOG.info("[AUTO-DELETE-IP] service: {}, ip: {}", service.getName(),
                            JacksonUtils.toJson(instance));
                    //删除逻辑,调取nacos api进行服务删除【自己调自己】
                    deleteIp(instance);
                }
            }

        } catch (Exception e) {
            Loggers.SRV_LOG.warn("Exception while processing client beat time out.", e);
        }

    }
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

响彻天堂丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值