> 文章列表 > nacos源码服务注册

nacos源码服务注册

nacos源码服务注册

nacos服务注册

  • 序言
  • 1.源码环境搭建
    • 1.1idea运行源码
    • 1.2 登录nacos
  • 2.服务注册分析
    • 2.1 客户端
      • 2.1.1容器启动监听
      • 2.1.2注册前初始化
      • 2.1.3注册服务
    • 2.2 服务端
      • 2.2.1注册
      • 2.2.2重试机制
  • 3.注意事项

序言

本文章是分析的是nacos版本2.2
这次版本是一次重大升级优化,由原来(临时服务)服务注册tcp改成grpc方式,减少资源消耗,服务推送由udp也改为grpc

1.源码环境搭建

  • 源码下载

1.1idea运行源码

  • 导入
  • clean-install-reimport
    nacos源码服务注册
  • 配置
    nacos源码服务注册
  • 启动
    单机运行 启动项配置 VM option
    nacos源码服务注册

1.2 登录nacos

nacos源码服务注册

2.服务注册分析

2.1 客户端

首先让我去实现一个服务注册,我们如何去做?
思考一:
是不是项目启动的时候进行服务注册
思考二:
springboot自动装载,是不是引入nacos依赖,就可以实现服务注册功能

按照上面的思路去分析注册大概过程就很清晰了

2.1.1容器启动监听

  • 自动加载入口
 @Bean@ConditionalOnBean({AutoServiceRegistrationProperties.class})public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration);}public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {super(serviceRegistry, autoServiceRegistrationProperties);this.registration = registration;}
  • web容器监听
public abstract class AbstractAutoServiceRegistration<R extends Registration> implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {
  • 綁定事件
    public void onApplicationEvent(WebServerInitializedEvent event) {this.bind(event);}/** @deprecated */@Deprecatedpublic void bind(WebServerInitializedEvent event) {ApplicationContext context = event.getApplicationContext();if (!(context instanceof ConfigurableWebServerApplicationContext) || !"management".equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) {this.port.compareAndSet(0, event.getWebServer().getPort());this.start();}}
  public void start() {if (!this.isEnabled()) {if (logger.isDebugEnabled()) {logger.debug("Discovery Lifecycle disabled. Not starting");}} else {if (!this.running.get()) {this.context.publishEvent(new InstancePreRegisteredEvent(this, this.getRegistration()));this.register();if (this.shouldRegisterManagement()) {this.registerManagement();}this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));this.running.compareAndSet(false, true);}}}

2.1.2注册前初始化

  • 获取namingservice服务
 public void register(Registration registration) {//创建namingservice服务NamingService namingService = this.namingService();//注册namingService.registerInstance(serviceId, group, instance);  }
  • 判断服务是否存在
  public NamingService getNamingService() {//不存在进行创建if (Objects.isNull(this.namingService)) {this.buildNamingService(this.nacosDiscoveryProperties.getNacosProperties());}return this.namingService;}
  • 创建NamingService服务
 NamingService naming = NamingFactory.createNamingService(properties);
 public NacosNamingService(Properties properties) throws NacosException {//nacosNamingService 客户端初始化init(properties);}private void init(Properties properties) throws NacosException {final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(properties);ValidatorUtils.checkInitParam(nacosClientProperties);//获取命名空间this.namespace = InitUtils.initNamespaceForNaming(nacosClientProperties);InitUtils.initSerialization();InitUtils.initWebRootContext(nacosClientProperties);initLogName(nacosClientProperties);//通知时间范围this.notifierEventScope = UUID.randomUUID().toString();//改变消息通知者this.changeNotifier = new InstancesChangeNotifier(this.notifierEventScope);//消息中心注册事件NotifyCenter.registerToPublisher(InstancesChangeEvent.class, 16384);//注册订阅者NotifyCenter.registerSubscriber(changeNotifier);//服务信息持有者this.serviceInfoHolder = new ServiceInfoHolder(namespace, this.notifierEventScope, nacosClientProperties);//创建客户端代理 去委托NamingClientProxyDelegatethis.clientProxy = new NamingClientProxyDelegate(this.namespace, serviceInfoHolder, nacosClientProperties, changeNotifier);}

2.1.3注册服务

   public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance {}", namespaceId, serviceName,instance);//缓存实例数据,增强可靠性redoService.cacheInstanceForRedo(serviceName, groupName, instance);//注册doRegisterService(serviceName, groupName, instance);}
 public void doRegisterService(String serviceName, String groupName, Instance instance) throws NacosException {InstanceRequest request = new InstanceRequest(namespaceId, serviceName, groupName,NamingRemoteConstants.REGISTER_INSTANCE, instance);//请求注册requestToServer(request, Response.class);//设置缓存数据状态为已经注册状态redoService.instanceRegistered(serviceName, groupName);}

2.2 服务端

2.2.1注册

    private InstanceResponse registerInstance(Service service, InstanceRequest request, RequestMeta meta)throws NacosException {clientOperationService.registerInstance(service, request.getInstance(), meta.getConnectionId());NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(),meta.getClientIp(), true, service.getNamespace(), service.getGroup(), service.getName(),request.getInstance().getIp(), request.getInstance().getPort()));return new InstanceResponse(NamingRemoteConstants.REGISTER_INSTANCE);}
    @Overridepublic void registerInstance(Service service, Instance instance, String clientId) throws NacosException {NamingUtils.checkInstanceIsLegal(instance);//获取当前的 Service (没有就新创建)Service singleton = ServiceManager.getInstance().getSingleton(service);if (!singleton.isEphemeral()) {throw new NacosRuntimeException(NacosException.INVALID_PARAM,String.format("Current service %s is persistent service, can't 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));}

2.2.2重试机制

为了确保注册成功,会从缓存中,把注册状态为失败的注册实例进行重新注册

   public NamingGrpcRedoService(NamingGrpcClientProxy clientProxy) {this.redoExecutor = new ScheduledThreadPoolExecutor(REDO_THREAD, new NameThreadFactory(REDO_THREAD_NAME));this.redoExecutor.scheduleWithFixedDelay(new RedoScheduledTask(clientProxy, this), DEFAULT_REDO_DELAY,DEFAULT_REDO_DELAY, TimeUnit.MILLISECONDS);}
    public void run() {if (!redoService.isConnected()) {LogUtils.NAMING_LOGGER.warn("Grpc Connection is disconnect, skip current redo task");return;}try {//重新注册redoForInstances();//重新订阅redoForSubscribes();} catch (Exception e) {LogUtils.NAMING_LOGGER.warn("Redo task run with unexpected exception: ", e);}}

3.注意事项

  • idea 运行源码找不到类
    这时,你需要clean 再install 最后reimport,就不会问题
    nacos源码服务注册

  • 启动时nacos没有以单例模式启动也会报错