首页>>后端>>java->实战 Cloud : Nacos Client 端主流程

实战 Cloud : Nacos Client 端主流程

时间:2023-12-01 本站 点击:0

一 . 前言

Nacos 请求时部分操作异常会直接宕掉 ,这个时候了解整个 Nacos Client 端的流程就至关重要.

Nacos 主流程主要分为以下几个部分 :

Nacos Client 端的启动和初始化

Nacos Client 端服务注册

Nacos Client 端服务发现

二 . Nacos Client 端的启动和初始化

Nacos 的自动装配类主要分为2个部分 :

NacosConfigAutoConfiguration

NacosDiscoveryAutoConfiguration

上一篇 Nacos 配置加载流程和优先级 已经看了配置的处理流程 , 这一篇主要关注 NacosDiscoveryAutoConfiguration

2.1 Nacos 的 Discovery 自动装配类

在 Nacos 的启动过程中 , 在配置类中初始化了如下几个对象 :

-newNacosServiceManager()-newNacosServiceDiscovery(discoveryProperties,nacosServiceManager):从缓存中获取列表-newNacosDiscoveryClient(nacosServiceDiscovery)

2.1.1 NacosWatch 的处理

//C-NacosWatchpublicvoidstart(){if(this.running.compareAndSet(false,true)){//Step1:构建EventListener对象EventListenereventListener=listenerMap.computeIfAbsent(buildKey(),event->newEventListener(){@OverridepublicvoidonEvent(Eventevent){if(eventinstanceofNamingEvent){List<Instance>instances=((NamingEvent)event).getInstances();Optional<Instance>instanceOptional=selectCurrentInstance(instances);instanceOptional.ifPresent(currentInstance->{resetIfNeeded(currentInstance);});}}});//Step2:通过NacosProperties准备NamingService对象->2.1.2Step2NamingServicenamingService=nacosServiceManager.getNamingService(properties.getNacosProperties());try{namingService.subscribe(properties.getService(),properties.getGroup(),Arrays.asList(properties.getClusterName()),eventListener);}catch(Exceptione){log.error("namingServicesubscribefailed,properties:{}",properties,e);}this.watchFuture=this.taskScheduler.scheduleWithFixedDelay(this::nacosServicesWatch,this.properties.getWatchDelay());}}

2.1.2 初始化流程

Step1 : NacosWatch 发起监听

//NamingServiceinit流程privatevoidinit(Propertiesproperties)throwsNacosException{ValidatorUtils.checkInitParam(properties);this.namespace=InitUtils.initNamespaceForNaming(properties);InitUtils.initSerialization();initServerAddr(properties);//初始化web容器InitUtils.initWebRootContext();//初始化缓存目录initCacheDir();//初始化log路径initLogName(properties);this.eventDispatcher=newEventDispatcher();//代理对象用于调用远程Serverthis.serverProxy=newNamingProxy(this.namespace,this.endpoint,this.serverList,properties);//用于向Nacos服务端发送已注册服务的心跳this.beatReactor=newBeatReactor(this.serverProxy,initClientBeatThreadCount(properties));//HostReactor用于获取、保存、更新各Service实例信息this.hostReactor=newHostReactor(this.eventDispatcher,this.serverProxy,beatReactor,this.cacheDir,isLoadCacheAtStart(properties),initPollingThreadCount(properties));}

Step 2 : NamingFactory 构建 NamingService

//实际上是通过反射生产最终的实例对象Class<?>driverImplClass=Class.forName("com.alibaba.nacos.client.naming.NacosNamingService");Constructorconstructor=driverImplClass.getConstructor(Properties.class);NamingServicevendorImpl=(NamingService)constructor.newInstance(properties);//工作空间privateStringnamespace;//privateStringendpoint;//服务列表对应的Server地址:localhost:8848privateStringserverList;//本地缓存地址privateStringcacheDir;//log名称:通常是naming.logprivateStringlogName;privateHostReactorhostReactor;privateBeatReactorbeatReactor;privateEventDispatchereventDispatcher;privateNamingProxyserverProxy;

Step 3 : EventDispatcher 添加监听器

publicvoidsubscribe(StringserviceName,StringgroupName,List<String>clusters,EventListenerlistener)throwsNacosException{//通过监听器来实现更新ServiceeventDispatcher.addListener(hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName,groupName),StringUtils.join(clusters,",")),StringUtils.join(clusters,","),listener);}publicvoidaddListener(ServiceInfoserviceInfo,Stringclusters,EventListenerlistener){//构建一个EventListener集合List<EventListener>observers=Collections.synchronizedList(newArrayList<EventListener>());observers.add(listener);//ConcurrentMap<String,List<EventListener>>observerMap//其中有个Notifier的线程,通过while循环持续的处理实例///nacos/v1/ns/instanceobservers=observerMap.putIfAbsent(ServiceInfo.getKey(serviceInfo.getName(),clusters),observers);if(observers!=null){observers.add(listener);}//change时刷新ServiceserviceChanged(serviceInfo);}

hostReactor.getServiceInfo 结果 :

三 . Nacos Client 端服务注册

服务注册涉及到如下流程 :

NacosRegistration:保存服务的基本数据信息

NacosServiceRegistry:实现服务注册

NacosServiceRegistryAutoConfiguration:Nacos自动配置类

Nacos 服务注册的起点是 @EnableDiscoveryClient , 其最终会调用 NacosAutoServiceRegistration :

AbstractAutoServiceRegistration

@Import(EnableDiscoveryClientImportSelector.class)public@interfaceEnableDiscoveryClient{//默认为true,开启后就会调用对应的AutoServiceRegistrationbooleanautoRegister()defaulttrue;}

3.1 start

不同的注册中心 , 会有不同的实现类 ,此处是对应 Nacos 的 NacosAutoServiceRegistration

//C-NacosAutoServiceRegistrationpublicvoidstart(){//如果未开启,则直接return//onlyinitializeifnonSecurePortisgreaterthan0anditisn'talreadyrunning//becauseofcontainerPortInitializerbelowif(!this.running.get()){this.context.publishEvent(newInstancePreRegisteredEvent(this,getRegistration()));//调用Registry发起注册:this.serviceRegistry.register(getRegistration());register();if(shouldRegisterManagement()){registerManagement();}this.context.publishEvent(newInstanceRegisteredEvent<>(this,getConfiguration()));this.running.compareAndSet(false,true);}}

3.2 NacosServiceRegistry 发起注册

publicvoidregister(Registrationregistration){if(StringUtils.isEmpty(registration.getServiceId())){return;}//构建当前的ServiceId和GroupNamingServicenamingService=namingService();StringserviceId=registration.getServiceId();Stringgroup=nacosDiscoveryProperties.getGroup();//包括IP,端口,分配名,元数据Instanceinstance=getNacosInstanceFromRegistration(registration);try{//注册当前实例,同时会添加心跳//serverProxy.registerService(groupedServiceName,groupName,instance);namingService.registerInstance(serviceId,group,instance);}catch(Exceptione){log.error("nacosregistry,{}registerfailed...{},",serviceId,registration.toString(),e);//rethrowaRuntimeExceptioniftheregistrationisfailed.//issue:https://github.com/alibaba/spring-cloud-alibaba/issues/1132rethrowRuntimeException(e);}}

四. 服务的发现

之前在Nacos 基础 中 , 我们大概看过一点 , 这里无非是再看一下

Nacos 的不同版本获取的方式是有很大区别的 , 这里主要针对 spring-cloud-starter-alibaba-nacos-discovery : 2.2.5 版本来看一下 .

4.1 Nacos Server 的发现

Step 1 : 发起的起点

privateList<NacosServer>getServers(){Stringgroup=discoveryProperties.getGroup();List<Instance>instances=discoveryProperties.namingServiceInstance().selectInstances(serviceId,group,true);returninstancesToServerList(instances);}

Step 2 : 发现的主流程

到这里就和之前的逻辑串起来了 , 后面就是反向调用 Nacos Server 中提供的接口即可

//C-NacosNamingServicepublicList<Instance>selectInstances(StringserviceName,StringgroupName,List<String>clusters,booleanhealthy,booleansubscribe)throwsNacosException{ServiceInfoserviceInfo=hostReactor.getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName,groupName),StringUtils.join(clusters,","));returnselectInstances(serviceInfo,healthy);}

这里获取中会从 Map<String, ServiceInfo> serviceInfoMap 中获取数据 , 下面来看一下 ServiceInfo 是如何获取的

//C-NacosWatchpublicvoidstart(){if(this.running.compareAndSet(false,true)){//Step1:构建EventListener对象EventListenereventListener=listenerMap.computeIfAbsent(buildKey(),event->newEventListener(){@OverridepublicvoidonEvent(Eventevent){if(eventinstanceofNamingEvent){List<Instance>instances=((NamingEvent)event).getInstances();Optional<Instance>instanceOptional=selectCurrentInstance(instances);instanceOptional.ifPresent(currentInstance->{resetIfNeeded(currentInstance);});}}});//Step2:通过NacosProperties准备NamingService对象->2.1.2Step2NamingServicenamingService=nacosServiceManager.getNamingService(properties.getNacosProperties());try{namingService.subscribe(properties.getService(),properties.getGroup(),Arrays.asList(properties.getClusterName()),eventListener);}catch(Exceptione){log.error("namingServicesubscribefailed,properties:{}",properties,e);}this.watchFuture=this.taskScheduler.scheduleWithFixedDelay(this::nacosServicesWatch,this.properties.getWatchDelay());}}0

总结

这篇文章有点简单 , 了解的不深 , 但是应该是很有用 , 出现问题在核心的地方打个断点 ,能节省很多时间

TODO : 流程图今天就不画了 , 后面有时间补一个


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/java/5492.html