nacos注册中心

nacos注册中心

1、服务注册:Nacos Client会通过发送REST请求的方式向Nacos Server注册自己的服务,提供自身的元数据。比如IP地址、端口等信息,Nacos Server接收到注册请求后,就会把这些元数据信息存储在一个双层的内存Map中。

1.1 实例是否是临时的如果是临时的?使用grpc通信:http通信,默认使用grpc通信

private NamingClientProxy getExecuteClientProxy(Instance instance) {
        return instance.isEphemeral() ? grpcClientProxy : httpClientProxy;
    }

nacos grpc通信

rpcclient端 registerservice实现

@Override
    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);//注册服务
    }

rpcclient向服务端发送请求

private <T extends Response> T requestToServer(AbstractNamingRequest request, Class<T> responseClass)
            throws NacosException {
        try {
            request.putAllHeader(getSecurityHeaders());
            request.putAllHeader(getSpasHeaders(
                    NamingUtils.getGroupedNameOptional(request.getServiceName(), request.getGroupName())));
            Response response =
                    requestTimeout < 0 ? rpcClient.request(request) : rpcClient.request(request, requestTimeout);
            if (ResponseCode.SUCCESS.getCode() != response.getResultCode()) {
                throw new NacosException(response.getErrorCode(), response.getMessage());
            }
            if (responseClass.isAssignableFrom(response.getClass())) {
                return (T) response;
            }
            NAMING_LOGGER.error("Server return unexpected response '{}', expected response should be '{}'",
                    response.getClass().getName(), responseClass.getName());
        } catch (Exception e) {
            throw new NacosException(NacosException.SERVER_ERROR, "Request nacos server failed: ", e);
        }
        throw new NacosException(NacosException.SERVER_ERROR, "Server return invalid response");
    }

rpcclient类内部静态代码块会扫描各个项目下的request 和response类

static {
        PayloadRegistry.init();
    }

  
    private static synchronized void scan() {
        if (initialized) {
            return;
        }
  
        List<String> requestScanPackage = Arrays
                .asList("com.alibaba.nacos.api.naming.remote.request", "com.alibaba.nacos.api.config.remote.request",
                        "com.alibaba.nacos.api.remote.request", "com.alibaba.nacos.naming.cluster.remote.request");
        for (String pkg : requestScanPackage) {
            Reflections reflections = new Reflections(pkg);
            Set<Class<? extends Request>> subTypesRequest = reflections.getSubTypesOf(Request.class);
            for (Class clazz : subTypesRequest) {
                register(clazz.getSimpleName(), clazz);
            }
        }
  
        List<String> responseScanPackage = Arrays
                .asList("com.alibaba.nacos.api.naming.remote.response",
                "com.alibaba.nacos.api.config.remote.response", "com.alibaba.nacos.api.remote.response",
                "com.alibaba.nacos.naming.cluster.remote.response");
        for (String pkg : responseScanPackage) {
            Reflections reflections = new Reflections(pkg);
            Set<Class<? extends Response>> subTypesOfResponse = reflections.getSubTypesOf(Response.class);
            for (Class clazz : subTypesOfResponse) {
                register(clazz.getSimpleName(), clazz);
            }
        }
  
        initialized = true;
    }

rpc请求的类型
nacos注册中心_第1张图片
nacos注册中心_第2张图片
nacos注册中心_第3张图片
nacos注册中心_第4张图片

每种请求都有对应的请求处理器,在server端启动的时候加载所有实现 RequestHandler的请求处理器以InstanceRequest为例,通过request.getType类型判断实例请求的类型然后进行分发处理.

@Override
@Secured(action = ActionTypes.WRITE, parser = NamingResourceParser.class)
public InstanceResponse handle(InstanceRequest request, RequestMeta meta) throws NacosException {
    Service service = Service
            .newService(request.getNamespace(), request.getGroupName(), request.getServiceName(), true);
    switch (request.getType()) {
        case NamingRemoteConstants.REGISTER_INSTANCE:
            return registerInstance(service, request, meta);
        case NamingRemoteConstants.DE_REGISTER_INSTANCE:
            return deregisterInstance(service, request, meta);
        default:
            throw new NacosException(NacosException.INVALID_PARAM,
                    String.format("Unsupported request type %s", request.getType()));
    }
}

nacos Event

nacos服务端内部通过事件机制处理响应的请求

@Override
    public void registerInstance(Service service, Instance instance, String clientId) {
        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();
        NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
        NotifyCenter
                .publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));
    }

Even内部维护了SEQUENCE和sequence属性实现事件sequence自动递增从而保证事件的顺序

/**
 * An abstract class for event.
 *
 * @author liaochuntao
 * @author zongtanghu
 */
@SuppressWarnings({"PMD.AbstractClassShouldStartWithAbstractNamingRule"})
public abstract class Event implements Serializable {
  
    private static final AtomicLong SEQUENCE = new AtomicLong(0);
  
    private final long sequence = SEQUENCE.getAndIncrement();
  
    /**
     * Event sequence number, which can be used to handle the sequence of events.
     *
     * @return sequence num, It's best to make sure it's monotone.
     */
    public long sequence() {
        return sequence;
    }
  
}

Event实现子类
nacos注册中心_第5张图片

其中Even有个SlowEven抽象子类,其子类实现如下
nacos注册中心_第6张图片

NotifyCenter#publishEvent

/**
     * Request publisher publish event Publishers load lazily, calling publisher.
     *
     * @param eventType class Instances type of the event type.
     * @param event     event instance.
     */
    private static boolean publishEvent(final Class eventType, final Event event) {
        if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {
            return INSTANCE.sharePublisher.publish(event);
        }
        
        final String topic = ClassUtils.getCanonicalName(eventType);
        
        //获取topic主题进行发送
        EventPublisher publisher = INSTANCE.publisherMap.get(topic);
        if (publisher != null) {
            return publisher.publish(event);
        }
        LOGGER.warn("There are no [{}] publishers for this event, please register", topic);
        return false;
    }

NamingEventPublisher#notifySubscriber 通知订阅者

@Override
    public void notifySubscriber(Subscriber subscriber, Event event) {
        if (Loggers.EVT_LOG.isDebugEnabled()) {
            Loggers.EVT_LOG.debug("[NotifyCenter] the {} will received by {}", event, subscriber);
        }
        final Runnable job = () -> subscriber.onEvent(event);
        final Executor executor = subscriber.executor();
        if (executor != null) {
            executor.execute(job);
        } else {
            try {
                job.run();
            } catch (Throwable e) {
                Loggers.EVT_LOG.error("Event callback exception: ", e);
            }
        }
    }

DefaultPublisher#receiveEvent

void receiveEvent(Event event) {
        final long currentEventSequence = event.sequence();
        
        if (!hasSubscriber()) {
            LOGGER.warn("[NotifyCenter] the {} is lost, because there is no subscriber.", event);
            return;
        }
        
        // Notification single event listener
        for (Subscriber subscriber : subscribers) {
            // Whether to ignore expiration events
            //是否忽略过期事件通过lastEventSequence判断
            if (subscriber.ignoreExpireEvent() && lastEventSequence > currentEventSequence) {
                LOGGER.debug("[NotifyCenter] the {} is unacceptable to this subscriber, because had expire",
                        event.getClass());
                continue;
            }
            
            // Because unifying smartSubscriber and subscriber, so here need to think of compatibility.
            // Remove original judge part of codes.
            notifySubscriber(subscriber, event);
        }
    }

nacos Task

//向delayTaskEngine 添加任务处理 通知订阅者
    @Override
    public void onEvent(Event event) {
        if (!upgradeJudgement.isUseGrpcFeatures()) {
            return;
        }
        if (event instanceof ServiceEvent.ServiceChangedEvent) {
            // If service changed, push to all subscribers.
            ServiceEvent.ServiceChangedEvent serviceChangedEvent = (ServiceEvent.ServiceChangedEvent) event;
            Service service = serviceChangedEvent.getService();
            delayTaskEngine.addTask(service, new PushDelayTask(service, PushConfig.getInstance().getPushTaskDelay()));
        } else if (event instanceof ServiceEvent.ServiceSubscribedEvent) {
            // If service is subscribed by one client, only push this client.
            ServiceEvent.ServiceSubscribedEvent subscribedEvent = (ServiceEvent.ServiceSubscribedEvent) event;
            Service service = subscribedEvent.getService();
            delayTaskEngine.addTask(service, new PushDelayTask(service, PushConfig.getInstance().getPushTaskDelay(),
                    subscribedEvent.getClientId()));
        }
    }

delayTaskEngine.addTask 如果任务中不存在task 就向队列中添加Task任务

@Override
    public void addTask(Object key, AbstractDelayTask newTask) {
        lock.lock();
        try {
            AbstractDelayTask existTask = tasks.get(key);
            if (null != existTask) {
                newTask.merge(existTask);
            }
            //不存在task怎添加task到concurrenthashmap中
            tasks.put(key, newTask);
        } finally {
            lock.unlock();
        }
    }

NacosDelayTaskExecuteEngine#processTasks负责处理task

/**
     * process tasks in execute engine.
     */
    protected void processTasks() {
        Collection keys = getAllTaskKeys();
        for (Object taskKey : keys) {
            AbstractDelayTask task = removeTask(taskKey);
            if (null == task) {
                continue;
            }
            NacosTaskProcessor processor = getProcessor(taskKey);
            if (null == processor) {
                getEngineLog().error("processor not found for task, so discarded. " + task);
                continue;
            }
            try {
                // ReAdd task if process failed
                if (!processor.process(task)) {
                    retryFailedTask(taskKey, task);
                }
            } catch (Throwable e) {
                getEngineLog().error("Nacos task execute error : " + e.toString(), e);
                retryFailedTask(taskKey, task);
            }
        }
    }
 
  

不同的processor对不同task处理的方式不同以PushDelayTaskExecuteEngine.PushDelayTaskProcessor#process为例

@Override
        public boolean process(NacosTask task) {
            PushDelayTask pushDelayTask = (PushDelayTask) task;
            Service service = pushDelayTask.getService();
            NamingExecuteTaskDispatcher.getInstance()
                    .dispatchAndExecuteTask(service, new PushExecuteTask(service, executeEngine, pushDelayTask));
            return true;
        }

dispatchAndExecuteTask会向队列中添加task 然后通过线程从队列中take执行task

@Override
    public void addTask(Object tag, AbstractExecuteTask task) {
        NacosTaskProcessor processor = getProcessor(tag);
        if (null != processor) {
            processor.process(task);
            return;
        }
        TaskExecuteWorker worker = getWorker(tag);
        worker.process(task);
    }
private class InnerWorker extends Thread {
      
        InnerWorker(String name) {
            setDaemon(false);
            setName(name);
        }
      
        @Override
        public void run() {
            while (!closed.get()) {
                try {
                    Runnable task = queue.take();
                    long begin = System.currentTimeMillis();
                    task.run();
                    long duration = System.currentTimeMillis() - begin;
                    if (duration > 1000L) {
                        log.warn("task {} takes {}ms", task, duration);
                    }
                } catch (Throwable e) {
                    log.error("[TASK-FAILED] " + e.toString(), e);
                }
            }
        }
    }

nacos http通信

nacos http通信和我们平常做web服务一样,client端调用restclient 端服务端用controller接受

nacos的chotrollers

nacos注册中心_第7张图片

你可能感兴趣的:(nacos,后端,java)