Nacos系列1---源码刨析naming服务的service核心管理类ServiceManager

本次解析的版本基于Nacos 1.1.0

功能说明

ServiceManager是nacos naming server中service核心管理类。在启动时会执行一次本地信息到其他服务器,while(true)发生改变的service队列内容进行本地更新,同时启动对com.alibaba.nacos.naming.domains.meta.前缀的key的监听;在运行过程中,执行controller接受的相关请求的功能,完成本地状态和远程服务器同步。

继承体系

首先看下整体结构,有一个大致印象

Nacos系列1---源码刨析naming服务的service核心管理类ServiceManager_第1张图片

具体刨析

主要总启动时执行和运行时执行的功能来分析。

启动分析

启动时的执行依赖于注解@PostConstruct的init()方法

    @PostConstruct
    public void init() {

        UtilsAndCommons.SERVICE_SYNCHRONIZATION_EXECUTOR.schedule(new ServiceReporter(), 60000, TimeUnit.MILLISECONDS);

        UtilsAndCommons.SERVICE_UPDATE_EXECUTOR.submit(new UpdatedServiceProcessor());

        try {
            Loggers.SRV_LOG.info("listen for service meta change");
            consistencyService.listen(KeyBuilder.SERVICE_META_KEY_PREFIX, this);
        } catch (NacosException e) {
            Loggers.SRV_LOG.error("listen for service meta change failed!");
        }
    }

第一行代码解析:bean初始化之后,执行一次调度,调度由ServiceReporter来执行。方法首先遍历serviceMap(Map>),如果size >0 且 distroMapper.responsible(serviceName)为true继续向下执行,通过getService(namespaceId, serviceName)获取到Service实例service,

如果service不为空,通过对该service下所有Instance实例组成的ip.getIp() + ":" + ip.getPort() + "_" + ip.getWeight() + "_"+ ip.isHealthy() + "_" + ip.getClusterName()执行md5来获得该service对应的checksum,再将service的checksum封装为Message实例msg,再将该消息同步到出自已以外的所有服务器。器质性同步的过程是通过async http post请求path /nacos/v1/ns/service/status来执行的,此处不关心执行结果,异步执行。

第一行代码思考:刚启动时执行一次同步数据到其他服务是否真的有必要?会不会导致数据落后呢?

 

第二行代码解析:启动一个新的UpdatedServiceProcessor线程并直接执行while (true),简单粗暴。该循环会一直尝试从LinkedBlockingDeque的toBeUpdatedServicesQueue实例来获取需要被更新的ServiceKey,该ServiceKey是由namespaceId+serviceName+serverIP+checksum组成的,而toBeUpdatedServicesQueue就是由外部consumer、provider、console、openapi对实例进行变更时,被该server收到,并offer进去的。获取到ServiceKey后继续向下执行,由GlobalExecutor启动一个新的ServiceUpdater线程,对本地执行线程状态更新updatedHealthStatus(namespaceId, serviceName, serverIP),具体执行逻辑是通过ServiceStatusSynchronizer实例synchronizer的get方法,通过NamingProxy.reqAPI方法对ServiceKey中包含的server发起http同步get调用,调用的path是/nacos/v1/ns/instance/statuses,并获返回result的数据组装成Message实例msg。将get到的实例msg进行解析和对比更新到service,并准备通过PushService的serviceChanged(service)来将更新推送到连接到本服务器的client,具体过程是通过调用ApplicationContext实例applicationContext的publishEvent()方法,来将封装成的ServiceChangeEvent实例发送出去。需要指出的是为了降低推送频率这里有一个futureMap.containsKey(UtilsAndCommons.assembleFullServiceName(service.getNamespaceId(), service.getName()))的判断,只有为false时才发送事件。

第二行代码思考:此处是通过死循环遍历队列发现service改变的通知,然后再去对应的server上去获取具体的改变,这样效率会不会低?直接把改变推送过来不就是更好。

 

try和catch模块中的代码解析:try和catch模块:该模块主要是启动对service meta change的监听,该模块由代码consistencyService.listen(KeyBuilder.SERVICE_META_KEY_PREFIX, this);来执行,

consistencyService是ConsistencyService的对象,实际运行过程中是由DelegateConsistencyServiceImpl类的实例来执行的。 具体逻辑如下:

@Override
public void listen(String key, RecordListener listener) throws NacosException {

    // this special key is listened by both:
    if (KeyBuilder.SERVICE_META_KEY_PREFIX.equals(key)) {
        persistentConsistencyService.listen(key, listener);
        ephemeralConsistencyService.listen(key, listener);
        return;
    }

    mapConsistencyService(key).listen(key, listener);
}

上述代码逻辑首先判断该key是否是special key,即以com.alibaba.nacos.naming.domains.meta.为前缀的key,

如果是,那么persistentConsistencyService和ephemeralConsistencyService都会启动监听;如果不是那么

根据key判断到底启动上述监听器中的哪一个。判断的具体逻辑在KeyBuilder中的matchEphemeralInstanceListKey方法中,

public static boolean matchEphemeralInstanceListKey(String key) {

        return key.startsWith(INSTANCE_LIST_KEY_PREFIX + EPHEMERAL_KEY_PREFIX);

    }

即,如果以com.alibaba.nacos.naming.iplist.ephemeral.为前缀的则启动ephemeralConsistencyService监听;其他情况则启动

persistentConsistencyService监听。

从上面传过来的常量来看是com.alibaba.nacos.naming.domains.meta.也就是2个监听器都会启动监听。

 

你可能感兴趣的:(中间件)