Nacos源码客户端系列第5篇服务中枢NacosNamingService

目录

NacosNamingService 流程图

NacosNamingService 功能概览

核心属性

初始化方法    

核心功能

 总结

学习目标:作为客户端的服务中枢类,需要知道它提供了哪些核心功能,跟它上下游的类是如何交互的。

简介:

NacosNamingService 是跟服务相关的核心管理类,提供了服务的上下线、服务实例查询、根据健康状态查询实例列表、根据随机权重算法查询单个健康实例、服务监听器订阅\取消订阅、分页查询服务列表等众多能力。

该类还在初始化时创建了另外3个分支核心类: 客户端心跳管理类BeatReactor、本地服务列表管理类HostReactor、服务事件管理类EventDispatcher、NacosServer 通信代理类NamingProxy。

NacosNamingService 流程图

NacosNamingService 功能概览

核心属性

public class NacosNamingService implements NamingService {
     // 服务所属命名空间
    private String namespace;

    // 提供一个服务地址 可以动态拉取serverList 
    // 区别于静态配置的serverList属性    
    private String endpoint;
    
    //服务列表以逗号隔开
    private String serverList;
    
    //服务列表的缓存和failover的目录
    private String cacheDir;

    //日志名称
    private String logName;

    //维护本地的服务列表管理
    private HostReactor hostReactor;

    //负责心跳任务管理
    private BeatReactor beatReactor;

    //负责服务变更事件的监听器管理
    private EventDispatcher eventDispatcher;

    //负责跟nacos server 的接口通信
    private NamingProxy serverProxy;
}

初始化方法    

初始化方法创建了4个非常重要的对象

//维护本地的服务列表管理 private HostReactor hostReactor;

//负责心跳任务管理 private BeatReactor beatReactor;

//负责跟nacos server 的接口通信 private NamingProxy serverProxy;

//负责服务变更事件的监听器管理 private EventDispatcher eventDispatcher;

initClientBeatThreadCount:执行心跳任务的线程数,建议配置该属性的值,因为如果不配置的话默认是cpu 逻辑核/2 如果是8C的机器就会创建4个核心线程, 实际上发送心跳的任务是5s一次所以该属性设置为1足够了。

initPollingThreadCount 服务定时更新的线程数,也建议配置该属性的值,因为如果不配置的话默认是cpu 逻辑核/2 如果是8C的机器就会创建4个核心线程, 如果微服务的服务数不多而且变更不是特别频繁的情况下 这个属性可以设置小一些。个人觉得一般设置成1是够了。因为即便1个线程用完了,线程池还会自动扩容。

核心功能

    ....
    //服务注册
    @Override
    public void registerInstance(String serviceName, String groupName, Instance 
       instance) throws NacosException {

        if (instance.isEphemeral()) {
            //创建心跳对象
            BeatInfo beatInfo = new BeatInfo();
            beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));
            beatInfo.setIp(instance.getIp());
            beatInfo.setPort(instance.getPort());
            beatInfo.setCluster(instance.getClusterName());
            beatInfo.setWeight(instance.getWeight());
            beatInfo.setMetadata(instance.getMetadata());
            beatInfo.setScheduled(false);
            // 默认5秒一次向服务端发送心跳报告
            long instanceInterval = instance.getInstanceHeartBeatInterval();
            beatInfo.setPeriod(instanceInterval == 0 ? DEFAULT_HEART_BEAT_INTERVAL : 
                    instanceInterval);

            //把心跳对象交给 beatReactor 定时执行 key 为groupname@@serviceName
            beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), 
                    beatInfo);
        }
        //serverProxy 完成跟远程服务器的注册请求
        serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), 
                    groupName, instance);
    }

    //服务下线
    @Override
    public void deregisterInstance(String serviceName, String groupName, Instance 
                instance) throws NacosException {
        //如果是临时节点 删除心跳任务
        if (instance.isEphemeral()) {
            beatReactor.removeBeatInfo(NamingUtils.getGroupedName(serviceName, 
               groupName), instance.getIp(), instance.getPort());
        }
        serverProxy.deregisterService(NamingUtils.getGroupedName(serviceName, 
               groupName), instance);
    }


   //查询服务下的实例列表
    @Override
    public List<Instance> getAllInstances(String serviceName, String groupName, 
                 List<String> clusters, boolean subscribe) throws NacosException {

        ServiceInfo serviceInfo;
        // 如果subscribe 为true 从本地获取[本地么有再从远程拉取]
        if (subscribe) {
            //优先从本地列表获取 
            serviceInfo = 
               hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, 
               groupName), StringUtils.join(clusters, ","));
        } else {
            // 如果subscribe 为false 直接从从远程拉取    
            serviceInfo = 
               hostReactor.getServiceInfoDirectlyFromServer(
               NamingUtils.getGroupedName(serviceName, groupName), 
               StringUtils.join(clusters, ","));
        }
        List<Instance> list;
        if (serviceInfo == null || CollectionUtils.isEmpty(list = 
               serviceInfo.getHosts())) {
            return new ArrayList<Instance>();
        }
        return list;
    }

    //根据  healthy 状态筛选实例
    @Override
    public List<Instance> selectInstances(String serviceName, String groupName, 
             List<String> clusters, boolean healthy, boolean subscribe) throws 
               NacosException {
        ServiceInfo serviceInfo;
        if (subscribe) {
            serviceInfo = 
                  hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, 
                  groupName), StringUtils.join(clusters, ","));
        } else {
            serviceInfo = 
            hostReactor.getServiceInfoDirectlyFromServer(
            NamingUtils.getGroupedName(serviceName, groupName), 
            StringUtils.join(clusters, ","));
        }
        return selectInstances(serviceInfo, healthy);
    }

  

    @Override
    public Instance selectOneHealthyInstance(String serviceName, String groupName, 
             List<String> clusters, boolean subscribe) throws NacosException {
        // 根据随机权重算法选择一个健康的节点
        if (subscribe) {
            return Balancer.RandomByWeight.selectHost(
                hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, 
                groupName), StringUtils.join(clusters, ",")));
        } else {
            return Balancer.RandomByWeight.selectHost(            
                hostReactor.getServiceInfoDirectlyFromServer(
                NamingUtils.getGroupedName(serviceName, groupName), 
                StringUtils.join(clusters, ",")));
        }
    }

    //订阅服务监听器
    @Override
    public void subscribe(String serviceName, String groupName, List<String> clusters, 
              EventListener listener) throws NacosException {
               eventDispatcher.addListener(
                    hostReactor.getServiceInfo(
                    NamingUtils.getGroupedName(serviceName, groupName),
                    StringUtils.join(clusters, ",")), 
                    StringUtils.join(clusters, ","), listener);
    }

    //取消服务监听器  
    @Override
    public void unsubscribe(String serviceName, String groupName, List<String> clusters, 
                EventListener listener) throws NacosException {
                eventDispatcher.removeListener(NamingUtils.getGroupedName(serviceName, 
                groupName), StringUtils.join(clusters, ","), listener);
    }

    //根据 groupName 和  selector 查询service 名称列表
    @Override
    public ListView<String> getServicesOfServer(int pageNo, int pageSize, String 
                groupName, AbstractSelector selector) throws NacosException {
        return serverProxy.getServiceList(pageNo, pageSize, groupName, selector);
    }

    //查询所有被订阅监听器的服务列表
    @Override
    public List<ServiceInfo> getSubscribeServices() {
        return eventDispatcher.getSubscribeServices();
    }
   
    //查询服务器的状态
    @Override
    public String getServerStatus() {
        return serverProxy.serverHealthy() ? "UP" : "DOWN";
    }
    
    //筛选健康 可用 权重 >0 的实例
    private List<Instance> selectInstances(ServiceInfo serviceInfo, boolean healthy) {
        List<Instance> list;
        if (serviceInfo == null || CollectionUtils.isEmpty(list = 
                serviceInfo.getHosts())) {
            return new ArrayList<Instance>();
        }

        Iterator<Instance> iterator = list.iterator();
        while (iterator.hasNext()) {
            Instance instance = iterator.next();
            if (healthy != instance.isHealthy() || !instance.isEnabled() || 
                  instance.getWeight() <= 0) {
                iterator.remove();
            }
        }

        return list;
    }

从代码NacosNamingService核心功能包括:

服务的上下线、服务实例查询、根据健康状态查询实例列表、根据随机权重算法查询单个健康实例、服务监听器订阅\取消订阅、分页查询服务列表等众多能力

其中Balancer.RandomByWeight.selectHost 随机权重 算法逻辑大家可以先在网上找下,后面我们单独开一篇讲下这个算法

 总结

通过NacosNamingService类的解析我们看到作为nacos client 的中枢类地位可谓非常重要。

所有的核心类都是在这里被初始化的。而且提供了完整的服务功能。

作为该类的分支,接下来的章节会单独介绍BeatReactor、HostReactor、NamingProxy、EventDispatcher等类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值