北京搜狗建网站的电话,wordpress简洁风模板,如何学做网站外包,cms框架Nacos服务注册
我们一个SpringCloud项目中集成了Nacos#xff0c;当项目启动成功后#xff0c;就可以在Nacos管理界面上看到我们项目的注册信息#xff0c;还可以看到项目的健康状态等等信息#xff1a; 那Nacos是什么时候进行了哪些操作的呢#xff1f;今天我们来一探究…Nacos服务注册
我们一个SpringCloud项目中集成了Nacos当项目启动成功后就可以在Nacos管理界面上看到我们项目的注册信息还可以看到项目的健康状态等等信息 那Nacos是什么时候进行了哪些操作的呢今天我们来一探究竟Let’s go!
Nacos客户端 如何集成SpringCloud Alibaba Nacos 在Maven项目中先引入依赖
!-- nacos注册依赖 --
dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactIdversion2.2.3.RELEASE/version
/dependencySpringBoot应用中的启动类
EnableDiscoveryClient
SpringBootApplication
public class ServiceApplication {public static void main(String[] args) {SpringApplication.run(ServiceApplication.class, args);}
}配置文件bootstrap.yaml
server:port: 9001
spring:application:name: ServiceAcloud:nacos:discovery:# NacosServer地址server-addr: 127.0.0.1:8848# NacosServer鉴权模式下的用户名username: nacos# NacosServer鉴权模式下的密码password: nacos第一步从哪里下手 了解过SpringBoot的starter的同学都知道引入一个starter我们可以去看这个starter中的spring.factories文件因为这里会告诉你SpringBoot在启动中会自动加载这个starter的哪些配置类。
org.springframework.boot.autoconfigure.EnableAutoConfiguration\com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,\com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,\com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,\com.alibaba.cloud.nacos.NacosServiceAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration\com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration
在自动加载的类中NacosServiceRegistryAutoConfiguration是处理服务实例自动注册的类。 走进服务自动注册 在NacosServiceRegistryAutoConfiguration中创建了NacosServiceRegistry、NacosRegistration、NacosAutoServiceRegistration的bean。
其中NacosServiceRegistry继承自SpringCloudCommon下的ServiceRegistry实现了服务注册、取消注册的能力 NacosRegistration继承自SpringCloudCommon的Registration表明它描述的是一个注册信息其中包含了服务的ip、端口、元信息、访问协议等信息 NacosAutoServiceRegistration就是利用上面的能力和数据在合适的时候被调用进行自动注册。
那什么时候才是合适的时候呢我们可以看到NacosAutoServiceRegistration继承自AbstractAutoServiceRegistration、实现了ApplicationListener接口那就说明需要被WebServerInitializedEvent事件驱动。WebServerInitializedEvent是ApplicationContext刷新完成且Web服务初始化完成后发布的一个事件。
接收到事件通知后就会进行注册
protected void register() {this.serviceRegistry.register(getRegistration());
}NacosServiceRegistry是怎样实现注册的 在Nacos中ServiceRegistry其实是使用的NamingService的能力完成注册的。
public void register(Registration registration) {....NamingService namingService namingService();String serviceId registration.getServiceId();String group nacosDiscoveryProperties.getGroup();Instance instance getNacosInstanceFromRegistration(registration);try {namingService.registerInstance(serviceId, group, instance);.....}catch (Exception e) {....}
}NamingService提供了服务注册下线、订阅消息查询等功能是很核心的一个能力提供者。
NamingService由NacosServiceManager负责管理具体由NamingFactory通过进行创建具体实现类是NacosNamingService。
NacosNamingService在实例化的时候创建了很多组件如 EventDispatcher 一个单线程的线程池死循环 承接Service信息改变的业务并通知到各个订阅了此Service的监听器 NamingProxy 两个核心线程的定时线程池 每隔30秒拉取远端Server列表 如果token过期重新登录获取token BeatReactor 定时线程池核心线程数量可自定义默认是核心数的一半最少1个核心线程数默认每隔5秒向服务端发送心跳 HostReactor 提供主动查询更新和被动接受服务信息推送的能力PushReceiver 一个单线程的定时线程池死循环接受来自服务端通过udp推送的数据并向服务端发送ack确认信息
在NacosNamingService的注册实例方法中
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {String groupedServiceName NamingUtils.getGroupedName(serviceName, groupName);if (instance.isEphemeral()) {BeatInfo beatInfo beatReactor.buildBeatInfo(groupedServiceName, instance);beatReactor.addBeatInfo(groupedServiceName, beatInfo);}serverProxy.registerService(groupedServiceName, groupName, instance);
}可以看到如果是临时实例可通过配置文件配置默认是临时实例那就会向线程池中丢一个心跳任务。
再通过NamingProxy进行注册
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {NAMING_LOGGER.info([REGISTER-SERVICE] {} registering service {} with instance: {}, namespaceId, serviceName,instance);final MapString, String params new HashMapString, String(16);params.put(CommonParams.NAMESPACE_ID, namespaceId);params.put(CommonParams.SERVICE_NAME, serviceName);params.put(CommonParams.GROUP_NAME, groupName);params.put(CommonParams.CLUSTER_NAME, instance.getClusterName());params.put(ip, instance.getIp());params.put(port, String.valueOf(instance.getPort()));params.put(weight, String.valueOf(instance.getWeight()));params.put(enable, String.valueOf(instance.isEnabled()));params.put(healthy, String.valueOf(instance.isHealthy()));params.put(ephemeral, String.valueOf(instance.isEphemeral()));params.put(metadata, JacksonUtils.toJson(instance.getMetadata()));reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.POST);}这里就是将服务实例信息通过标准的Restful接口和Server进行通信。
Nacos服务端
UtilAndComs.nacosUrlInstance对应的请求路径是/nacos/v1/ns/instance。
在Nacos源码中 这个请求的处理是在naming模块下的InstanceControllerV2#register中进行的。
CanDistro
PostMapping
Secured(action ActionTypes.WRITE)
public ResultString register(InstanceForm instanceForm) throws NacosException {// 检查实例的参数instanceForm.validate();// 检查实例的权重checkWeight(instanceForm.getWeight());// 构造一个实例对象Instance instance buildInstance(instanceForm);// 注册instanceServiceV2.registerInstance(instanceForm.getNamespaceId(), buildCompositeServiceName(instanceForm), instance);// 发送RegisterInstanceTraceEvent事件NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(), ,false, instanceForm.getNamespaceId(), instanceForm.getGroupName(), instanceForm.getServiceName(),instance.getIp(), instance.getPort()));return Result.success(ok);
}上面代码就是检查参数构造Instance服务实例对象使用instanceServiceV2类进行注册再发布RegisterInstanceTraceEvent事件。
接下来进入instanceServiceV2.registerInstance看看
Override
public void registerInstance(Service service, Instance instance, String clientId) throws NacosException {NamingUtils.checkInstanceIsLegal(instance);Service singleton ServiceManager.getInstance().getSingleton(service);if (!singleton.isEphemeral()) {throw new NacosRuntimeException(NacosException.INVALID_PARAM,String.format(Current service %s is persistent service, cant register ephemeral instance.,singleton.getGroupedServiceName()));}Client client clientManager.getClient(clientId);if (!clientIsLegal(client, clientId)) {return;}InstancePublishInfo instanceInfo getPublishInfo(instance);client.addServiceInstance(singleton, instanceInfo);client.setLastUpdatedTime();client.recalculateRevision();NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));NotifyCenter.publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));
}上述源码其实就三个步骤
1、将Service的信息维护到ServiceManager中。
2、从ClientManager中获取Client信息。
3、向NotifyCenter发送事件通知。
Nacos Web
在Nacos的后台web系统中服务列表是通过GET /nacos/v1/ns/catalog/services获取的我们可以在Nacos的naming模块下找到相应的控制类的处理逻辑
Secured(action ActionTypes.READ)
GetMapping(/services)
public Object listDetail(RequestParam(required false) boolean withInstances,RequestParam(defaultValue Constants.DEFAULT_NAMESPACE_ID) String namespaceId,RequestParam(required false) int pageNo, RequestParam(required false) int pageSize,RequestParam(name serviceNameParam, defaultValue StringUtils.EMPTY) String serviceName,RequestParam(name groupNameParam, defaultValue StringUtils.EMPTY) String groupName,RequestParam(name instance, defaultValue StringUtils.EMPTY) String containedInstance,RequestParam(required false) boolean hasIpCount) throws NacosException {if (withInstances) {return judgeCatalogService().pageListServiceDetail(namespaceId, groupName, serviceName, pageNo, pageSize);}return judgeCatalogService().pageListService(namespaceId, groupName, serviceName, pageNo, pageSize, containedInstance, hasIpCount);
}跟踪源码最终我们可以确认到最基础的数据是从ServiceManager的namespaceSingletonMaps中获取到的namespaceSingletonMaps是一个Map存储了namespace和Service的对应关系。
最后放上一张整个过程的示意图 总结
今天的文章里面讲解了一个SpringBoot应用是怎样注册到NacosServer中的以及Nacos管理界面的数据来源。
文中涉及到了SpringCloudCommon的知识这里可以简单提一下SpringCloudCommon是SpringCloud的一系列标准其抽象了服务注册与发现、负载均衡器、熔断等模型SpringCloudAlibaba只是按照这个标准具体的一个实现如SpringCloudNetflix就是另一套实现。
在整个Nacos的体系中还有很多技术是待深入的比如NamingService中各个组件具体的实现方式NotifyCenter的实现方式服务信息的持久化、保证数据一致性的策略等等有兴趣的小伙伴可以持续关注我的后续文章。
最后放上一张Nacos架构图带你敲响Nacos的大门。