Nacos服务注册与发现中心之服务提供者心跳机制(服务端代码)

上篇说了Nacos服务注册与发现中心的服务注册在服务端的代码,接下来看服务提供者与Nacos服务器之间心跳机制的服务端的代码


入口URI

在介绍服务注册者注册服务的客户端代码的文章中,有讲过:服务提供者在注册服务的同时会启动一个定时任务,每5秒会发送一次心跳请求到Nacos服务端。通过客户端的源码我们可以得出,该URI为:/nacos/v1/ns/instance/beat, 请求方法为PUT。

一、InstanceController

此URI的处理类,依旧的InstanceController,我们先来看Controller层的源码:

 @CanDistro
    @RequestMapping(value = "/beat", method = RequestMethod.PUT)
    public JSONObject beat(HttpServletRequest request) throws Exception {
		
		// ... 省略不关心的代码
		
		// 1
        Instance instance = serviceManager.getInstance(namespaceId, serviceName, clientBeat.getCluster(), clientBeat.getIp(),
            clientBeat.getPort());

        if (instance == null) {
            instance = new Instance();
            instance.setPort(clientBeat.getPort());
            instance.setIp(clientBeat.getIp());
            instance.setWeight(clientBeat.getWeight());
            instance.setMetadata(clientBeat.getMetadata());
            instance.setClusterName(clusterName);
            instance.setServiceName(serviceName);
            instance.setInstanceId(instance.generateInstanceId());
            instance.setEphemeral(clientBeat.isEphemeral());

            serviceManager.registerInstance(namespaceId, serviceName, instance);
        }
		
        Service service = serviceManager.getService(namespaceId, serviceName);

        if (service == null) {
            throw new NacosException(NacosException.SERVER_ERROR, "service not found: " + serviceName + "@" + namespaceId);
        }
		
		// 2
        service.processClientBeat(clientBeat);

        return result;
    }

我们将代码关键处标上1,2标注。
我们先看1处的代码:通过NameSpaceId,serviceName,实例的ip和端口号,尝试获取实例在服务端的信息,如果获取不到,会先进行一次服务的注册,至于服务注册的代码,我们在上篇文章已经进行过讲解了。
在标注2处,会进行真正的心跳处理。

service.processClientBeat(clientBeat);

我们再来看service.processClientBeat(clientBeat);的代码

    public void processClientBeat(final RsInfo rsInfo) {
        ClientBeatProcessor clientBeatProcessor = new ClientBeatProcessor();
        clientBeatProcessor.setService(this);
        clientBeatProcessor.setRsInfo(rsInfo);
        HealthCheckReactor.scheduleNow(clientBeatProcessor);
    }

可以看到,这里创建了一个异步任务ClientBeatProcessor,我们再来看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) {
            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.getNamespaceId(), this.service.getName());
                    }
                }
            }
        }
    }

此处可以看到,任务的主要逻辑是先获取到对应的实例列表,再遍历去获取ip和端口号相同的实例,然后更新实例的最后一次心跳时间和更新实例的健康状态,最后会进行一次服务状态变更的通过:这里是通过UDP的方式通知服务消费者,具体逻辑会在介绍服务消费者时再细说

END

可以看到服务端心跳的代码还是相对简单清晰的,下一篇将会开始介绍服务消费者相关的逻辑以及源码。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值