nacos注册中心之服务注册

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

5 nacos注册中心之服务注册

基于nacos 1.1.4 的源码分析

Nacos提供了SDK和Open API的形式实现服务注册,两种方式本质都是一样的,SDK方式提供了一种访问的封装,底层是基于HTTP 协议完成请求的,所有我们直接基于Open API请求方式分析一下服务端的服务注册原理。

/nacos/v1/ns/instance
复制代码

服务注册对外提供的服务接口请求地址为nacos/v1/ns/instance,实现代码为nacos-naming下的InstanceController类:

@RestController
@RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance")
public class InstanceController {
    @CanDistro
    @PostMapping
    public String register(HttpServletRequest request) throws Exception {

        String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
        String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);

        serviceManager.registerInstance(namespaceId, serviceName, parseInstance(request));
        return "ok";
    }
}
复制代码

调用registerInstance方法:

public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {

    createEmptyService(namespaceId, serviceName, instance.isEphemeral());

    Service service = getService(namespaceId, serviceName);

    if (service == null) {
        throw new NacosException(NacosException.INVALID_PARAM,
            "service not found, namespace: " + namespaceId + ", service: " + serviceName);
    }

    addInstance(namespaceId, serviceName, instance.isEphemeral(), instance);
}
复制代码
  1. 创建一个空服务,实际是初始化serviceMap
  2. getService:从serviceMap中根据namespaceId和serviceName得到服务对象
  3. 调用addInstance添加服务实例。

createEmptyService

createEmptyService用来创建空服务,调用createServiceIfAbsent

public void createServiceIfAbsent(String namespaceId, String serviceName, boolean local, Cluster cluster) throws NacosException {
    Service service = getService(namespaceId, serviceName);
    if (service == null) {

        Loggers.SRV_LOG.info("creating empty service {}:{}", namespaceId, serviceName);
        service = new Service();
        service.setName(serviceName);
        service.setNamespaceId(namespaceId);
        service.setGroupName(NamingUtils.getGroupName(serviceName));
        // now validate the service. if failed, exception will be thrown
        service.setLastModifiedMillis(System.currentTimeMillis());
        service.recalculateChecksum();
        if (cluster != null) {
            cluster.setService(service);
            service.getClusterMap().put(cluster.getName(), cluster);
        }
        service.validate();

        putServiceAndInit(service);
        if (!local) {
            addOrReplaceService(service);
        }
    }
}
复制代码
  1. 根据namespaceId和serviceName从缓存中获取Service实例
  2. 如果没有,创建并调用putServiceAndInit()保存到缓存中。

putServiceAndInit方法:

private void putServiceAndInit(Service service) throws NacosException {
    putService(service);
    service.init();
    consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), true), service);
    consistencyService.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), false), service);
    Loggers.SRV_LOG.info("[NEW-SERVICE] {}", service.toJSON());
}
复制代码
  1. 通过putService方法将服务缓存到内存
  2. service.init();建立心跳检测机制,通过定时任务不断检测当前服务下所有实例最后发送心跳包的时间。如果超时,则设置healthy为false表示服务不健康,并发送服务变更事件。
  3. consistencyService.listen实现数据一致性的监听

总结:

Nacos提供了SDK和Open API的形式实现服务注册,两种方式本质都是一样的

服务注册对外提供的服务接口请求地址为nacos/v1/ns/instance

服务注册过程:

  1. nacos客户端通过Open API的形式发送服务注册请求
  2. 服务端收到请求:
    • 构建一个Service对象保存到Map集合中
    • 使用定时任务对当前服务下的所有实例建立心跳检测机制。
    • 基于数据一致性协议将服务数据进行同步。

nacos的服务注册对我们很重要,我们要理解其中的原理和注册流程,然后分析看源码,从而更好的理解nacos是怎么实现服务的注册的,这样我们才能理解透彻nacos的运作机制,以后在我们工作中遇到什么问题,我们能够及时排查,快速定位,这样我们才能在工作和学习中更好的提高效率完成任务。 你觉得这篇文章不错的话,请留言点赞评论~~

猜你喜欢

转载自juejin.im/post/7017634048822476808