Nacos源码2.03二、服务注册

一.NacosPropertySourceLocator

当前类实现了PropertySourceLocator,主要用于配置文件的拓展,从配置中心读取配置
private void loadApplicationConfiguration(CompositePropertySource compositePropertySource, String dataIdPrefix, NacosConfigProperties properties, Environment environment) {
        String fileExtension = properties.getFileExtension();
        String nacosGroup = properties.getGroup();
        //1.1读取配置
        this.loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup, fileExtension, true);
        this.loadNacosDataIfPresent(compositePropertySource, dataIdPrefix + "." + fileExtension, nacosGroup, fileExtension, true);
        String[] var7 = environment.getActiveProfiles();
        int var8 = var7.length;

        for(int var9 = 0; var9 < var8; ++var9) {
            String profile = var7[var9];
            String dataId = dataIdPrefix + "-" + profile + "." + fileExtension;
            this.loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup, fileExtension, true);
        }

    }

二.RpcClient

在获取客户端配置的时候会启动Rpc客户端
public final void start() throws NacosException {
		//将当前客户端跟改为启动状态
        boolean success = this.rpcClientStatus.compareAndSet(RpcClientStatus.INITIALIZED, RpcClientStatus.STARTING);
        if (success) {
        	//创建定时任务线程池(包含两个守护线程)
            this.clientEventExecutor = new ScheduledThreadPoolExecutor(2, new ThreadFactory() {
                public Thread newThread(Runnable r) {
                    Thread t = new Thread(r);
                    t.setName("com.alibaba.nacos.client.remote.worker");
                    t.setDaemon(true);
                    return t;
                }
            });
            this.clientEventExecutor.submit(new Runnable() {
                public void run() {
                    while(!RpcClient.this.clientEventExecutor.isTerminated() && !RpcClient.this.clientEventExecutor.isShutdown()) {
                        RpcClient.ConnectionEvent take = null;

                        try {
                            take = (RpcClient.ConnectionEvent)RpcClient.this.eventLinkedBlockingQueue.take();
                            if (take.isConnected()) {
                                RpcClient.this.notifyConnected();
                            } else if (take.isDisConnected()) {
                                RpcClient.this.notifyDisConnected();
                            }
                        } catch (Throwable var3) {
                        }
                    }

                }
            });
            this.clientEventExecutor.submit(new Runnable() {
                public void run() {
                    while(true) {
                        while(true) {
                            while(true) {
                                while(true) {
                                    while(true) {
                                        try {
                                            RpcClient.ReconnectContext reconnectContext;
                                            boolean serverExist;
                                            label69: {
                                                if (!RpcClient.this.isShutdown()) {
                                                    reconnectContext = (RpcClient.ReconnectContext)RpcClient.this.reconnectionSignal.poll(RpcClient.this.keepAliveTime, TimeUnit.MILLISECONDS);
                                                    if (reconnectContext != null) {
                                                        break label69;
                                                    }

                                                    if (System.currentTimeMillis() - RpcClient.this.lastActiveTimeStamp < RpcClient.this.keepAliveTime) {
                                                        continue;
                                                    }

                                                    serverExist = RpcClient.this.healthCheck();
                                                    if (serverExist) {
                                                        RpcClient.this.lastActiveTimeStamp = System.currentTimeMillis();
                                                        continue;
                                                    }

                                                    if (RpcClient.this.currentConnection == null) {
                                                        continue;
                                                    }

                                                    LoggerUtils.printIfInfoEnabled(RpcClient.LOGGER, "[{}]Server healthy check fail,currentConnection={}", new Object[]{RpcClient.this.name, RpcClient.this.currentConnection.getConnectionId()});
                                                    RpcClientStatus rpcClientStatus = (RpcClientStatus)RpcClient.this.rpcClientStatus.get();
                                                    if (!RpcClientStatus.SHUTDOWN.equals(rpcClientStatus)) {
                                                        boolean success = RpcClient.this.rpcClientStatus.compareAndSet(rpcClientStatus, RpcClientStatus.UNHEALTHY);
                                                        if (!success) {
                                                            continue;
                                                        }

                                                        reconnectContext = RpcClient.this.new ReconnectContext((RpcClient.ServerInfo)null, false);
                                                        break label69;
                                                    }
                                                }

                                                return;
                                            }

                                            if (reconnectContext.serverInfo != null) {
                                                serverExist = false;
                                                Iterator var7 = RpcClient.this.getServerListFactory().getServerList().iterator();

                                                while(var7.hasNext()) {
                                                    String server = (String)var7.next();
                                                    RpcClient.ServerInfo serverInfo = RpcClient.this.resolveServerInfo(server);
                                                    if (serverInfo.getServerIp().equals(reconnectContext.serverInfo.getServerIp())) {
                                                        serverExist = true;
                                                        reconnectContext.serverInfo.serverPort = serverInfo.serverPort;
                                                        break;
                                                    }
                                                }

                                                if (!serverExist) {
                                                    LoggerUtils.printIfInfoEnabled(RpcClient.LOGGER, "[{}] Recommend server is not in server list ,ignore recommend server {}", new Object[]{RpcClient.this.name, reconnectContext.serverInfo.getAddress()});
                                                    reconnectContext.serverInfo = null;
                                                }
                                            }

                                            RpcClient.this.reconnect(reconnectContext.serverInfo, reconnectContext.onRequestFail);
                                        } catch (Throwable var6) {
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            });
            Connection connectToServer = null;
            this.rpcClientStatus.set(RpcClientStatus.STARTING);
            //失败重试次数
            int startUpRetryTimes = 3;

            while(startUpRetryTimes > 0 && connectToServer == null) {
                try {
                    --startUpRetryTimes;
                    RpcClient.ServerInfo serverInfo = this.nextRpcServer();
                    LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Try to connect to server on start up, server: {}", new Object[]{this.name, serverInfo});
                    connectToServer = this.connectToServer(serverInfo);
                } catch (Throwable var5) {
                    LoggerUtils.printIfWarnEnabled(LOGGER, "[{}]Fail to connect to server on start up, error message={}, start up retry times left: {}", new Object[]{this.name, var5.getMessage(), startUpRetryTimes});
                }
            }

            if (connectToServer != null) {
                LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Success to connect to server [{}] on start up,connectionId={}", new Object[]{this.name, connectToServer.serverInfo.getAddress(), connectToServer.getConnectionId()});
                this.currentConnection = connectToServer;
                this.rpcClientStatus.set(RpcClientStatus.RUNNING);
                this.eventLinkedBlockingQueue.offer(new RpcClient.ConnectionEvent(1));
            } else {
                this.switchServerAsync();
            }

            this.registerServerRequestHandler(new RpcClient.ConnectResetRequestHandler());
            this.registerServerRequestHandler(new ServerRequestHandler() {
                public Response requestReply(Request request) {
                    return request instanceof ClientDetectionRequest ? new ClientDetectionResponse() : null;
                }
            });
        }
    }

GrpcClient

public Connection connectToServer(ServerInfo serverInfo) {
        try {
            int port;
            if (this.grpcExecutor == null) {
                port = ThreadUtils.getSuitableThreadCount(8);
                this.grpcExecutor = new ThreadPoolExecutor(port, port, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(10000), (new ThreadFactoryBuilder()).setDaemon(true).setNameFormat("nacos-grpc-client-executor-%d").build());
                this.grpcExecutor.allowCoreThreadTimeOut(true);
            }

            port = serverInfo.getServerPort() + this.rpcPortOffset();
            RequestFutureStub newChannelStubTemp = this.createNewChannelStub(serverInfo.getServerIp(), port);
            if (newChannelStubTemp != null) {
                Response response = this.serverCheck(serverInfo.getServerIp(), port, newChannelStubTemp);
                if (response != null && response instanceof ServerCheckResponse) {
                    BiRequestStreamStub biRequestStreamStub = BiRequestStreamGrpc.newStub(newChannelStubTemp.getChannel());
                    GrpcConnection grpcConn = new GrpcConnection(serverInfo, this.grpcExecutor);
                    grpcConn.setConnectionId(((ServerCheckResponse)response).getConnectionId());
                    StreamObserver<Payload> payloadStreamObserver = this.bindRequestStream(biRequestStreamStub, grpcConn);
                    grpcConn.setPayloadStreamObserver(payloadStreamObserver);
                    grpcConn.setGrpcFutureServiceStub(newChannelStubTemp);
                    grpcConn.setChannel((ManagedChannel)newChannelStubTemp.getChannel());
                    ConnectionSetupRequest conSetupRequest = new ConnectionSetupRequest();
                    conSetupRequest.setClientVersion(VersionUtils.getFullClientVersion());
                    conSetupRequest.setLabels(super.getLabels());
                    conSetupRequest.setAbilities(super.clientAbilities);
                    conSetupRequest.setTenant(super.getTenant());
                    grpcConn.sendRequest(conSetupRequest);
                    Thread.sleep(100L);
                    return grpcConn;
                } else {
                    this.shuntDownChannel((ManagedChannel)newChannelStubTemp.getChannel());
                    return null;
                }
            } else {
                return null;
            }
        } catch (Exception var9) {
            LOGGER.error("[{}]Fail to connect to server!,error={}", this.getName(), var9);
            return null;
        }
    }

NacosWatch

SmartLifecycle 接口。当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法
NacosWatch实现了该接口,主要作用试发布事件

NacosServiceRegistry

#spring容器完成之后会发布事件,当前这个接口实现了服务注册接口AbstractAutoServiceRegistration
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
    private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class);
    private final NacosDiscoveryProperties nacosDiscoveryProperties;
    private final NamingService namingService;

    public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
        this.nacosDiscoveryProperties = nacosDiscoveryProperties;
        this.namingService = nacosDiscoveryProperties.namingServiceInstance();
    }
	#Registration在实例化的时候会把ip超时时间,心跳超时时间等一些数据放入metadata中
    public void register(Registration registration) {
        if (StringUtils.isEmpty(registration.getServiceId())) {
            log.warn("No service to register for nacos client...");
        } else {
            String serviceId = registration.getServiceId();
            Instance instance = this.getNacosInstanceFromRegistration(registration);

            try {
                this.namingService.registerInstance(serviceId, instance);
                log.info("nacos registry, {} {}:{} register finished", new Object[]{serviceId, instance.getIp(), instance.getPort()});
            } catch (Exception var5) {
                log.error("nacos registry, {} register failed...{},", new Object[]{serviceId, registration.toString(), var5});
            }

        }
    }
}

一、创建心跳信息信息,执行心跳定时任务

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);
            long instanceInterval = instance.getInstanceHeartBeatInterval();
            // 设置心跳检测的时间周期,默认是5s
            // 可以通过属性spring.cloud.nacos.discovery.heartBeatInterval配置
            beatInfo.setPeriod(instanceInterval == 0L ? DEFAULT_HEART_BEAT_INTERVAL : instanceInterval);
            //创建心跳定时任务
            this.beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);
        }

        this.serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);
    }

在这里插入图片描述
1.1创建心跳定时任务(默认为5秒)

public void addBeatInfo(String serviceName, BeatInfo beatInfo) {
        LogUtils.NAMING_LOGGER.info("[BEAT] adding beat: {} to beat map.", beatInfo);
        //将服务名 ip 端口作为key 心跳信息作为value存入map
        this.dom2Beat.put(this.buildKey(serviceName, beatInfo.getIp(), beatInfo.getPort()), beatInfo);
        //创建定时任务
        this.executorService.schedule(new BeatReactor.BeatTask(beatInfo), 0L, TimeUnit.MILLISECONDS);
		#创建prometheus监视器监控心跳        
        MetricsMonitor.getDom2BeatSizeMonitor().set((double)this.dom2Beat.size());
    }

1.2线程池的创建

#默认取namingClientBeatThreadCount数量如果没有根据下面算法得出
#线程数的定义算法
Runtime.getRuntime().availableProcessors() > 1 ? Runtime.getRuntime().availableProcessors() / 2 : 1


#线程池的创建是在对象创建的构造器注入的,默认为8个(守护线程)
public BeatReactor(NamingProxy serverProxy, int threadCount) {
        this.dom2Beat = new ConcurrentHashMap();
        this.serverProxy = serverProxy;
        this.executorService = new ScheduledThreadPoolExecutor(threadCount, new ThreadFactory() {
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setDaemon(true);
                thread.setName("com.alibaba.nacos.naming.beat.sender");
                return thread;
            }
        });
    }

1.3线程任务的创建

class BeatTask implements Runnable {
        BeatInfo beatInfo;

        public BeatTask(BeatInfo beatInfo) {
            this.beatInfo = beatInfo;
        }

        public void run() {
            if (!this.beatInfo.isStopped()) {
            	//向客户端的心跳接口请求/instance/beat
                long result = BeatReactor.this.serverProxy.sendBeat(this.beatInfo);
                //获取下一次的请求时间
                long nextTime = result > 0L ? result : this.beatInfo.getPeriod();
                //将任务放入定时任务池中(守护线程)
                BeatReactor.this.executorService.schedule(BeatReactor.this.new BeatTask(this.beatInfo), nextTime, TimeUnit.MILLISECONDS);
            }
        }
    }

2、创建监视器

 private static Gauge nacosMonitor = (Gauge)((Builder)((Builder)((Builder)Gauge.build().name("nacos_monitor")).labelNames(new String[]{"module", "name"})).help("nacos_monitor")).register();
	
	//设置监视器
	public static Child getDom2BeatSizeMonitor() {
        return (Child)nacosMonitor.labels(new String[]{"naming", "dom2BeatSize"});
    }

二.注册服务调用

2.1参数封装

public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
        LogUtils.NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}", new Object[]{this.namespaceId, serviceName, instance});
        Map<String, String> params = new HashMap(9);
        params.put("namespaceId", this.namespaceId);
        params.put("serviceName", serviceName);
        params.put("groupName", groupName);
        params.put("clusterName", 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", JSON.toJSONString(instance.getMetadata()));
        this.reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, (String)"POST");
    }

2.2采用故障转移算法,请求调用注册地址/nacos/v1/ns/instance

public String reqAPI(String api, Map<String, String> params, List<String> servers, String method) {
        params.put("namespaceId", this.getNamespaceId());
        if (CollectionUtils.isEmpty(servers) && StringUtils.isEmpty(this.nacosDomain)) {
            throw new IllegalArgumentException("no server available");
        } else {
            Exception exception = new Exception();
            if (servers != null && !servers.isEmpty()) {
                Random random = new Random(System.currentTimeMillis());//根据当前时间创建随机数
                int index = random.nextInt(servers.size());//根据服务数量获取随机数

                for(int i = 0; i < servers.size(); ++i) {
                    String server = (String)servers.get(index);//获取随机的注册地址

                    try {
                        return this.callServer(api, params, server, method);//调用nacos注册中心
                    } catch (NacosException var11) {
                        exception = var11;
                        LogUtils.NAMING_LOGGER.error("request {} failed.", server, var11);
                    } catch (Exception var12) {
                        exception = var12;
                        LogUtils.NAMING_LOGGER.error("request {} failed.", server, var12);
                    }

                    index = (index + 1) % servers.size();//出现异常请求下一个
                }

                throw new IllegalStateException("failed to req API:" + api + " after all servers(" + servers + ") tried: " + ((Exception)exception).getMessage());
            } else {
                int i = 0;

                while(i < 3) {
                    try {
                        return this.callServer(api, params, this.nacosDomain);
                    } catch (Exception var13) {
                        exception = var13;
                        LogUtils.NAMING_LOGGER.error("[NA] req api:" + api + " failed, server(" + this.nacosDomain, var13);
                        ++i;
                    }
                }

                throw new IllegalStateException("failed to req API:/api/" + api + " after all servers(" + servers + ") tried: " + ((Exception)exception).getMessage());
            }
        }
    }
public String callServer(String api, Map<String, String> params, String curServer, String method) throws NacosException {
        long start = System.currentTimeMillis();
        long end = 0L;
        this.checkSignature(params);
        List<String> headers = this.builderHeaders();
        String url;//请求路径为:/nacos/v1/ns/instance
        if (!curServer.startsWith("https://") && !curServer.startsWith("http://")) {
            if (!curServer.contains(":")) {
                curServer = curServer + ":" + this.serverPort;
            }

            url = HttpClient.getPrefix() + curServer + api;
        } else {
            url = curServer + api;
        }

        HttpResult result = HttpClient.request(url, headers, params, "UTF-8", method);
        end = System.currentTimeMillis();
        MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(result.code)).observe((double)(end - start));
        if (200 == result.code) {
            return result.content;
        } else if (304 == result.code) {
            return "";
        } else {
            throw new NacosException(500, "failed to req API:" + curServer + api + ". code:" + result.code + " msg: " + result.content);
        }
    }

3.Nacos Server端接收/nacos/v1/ns/instance请求

	@CanDistro
    @PostMapping
    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
    public String register(HttpServletRequest request) throws Exception {
        
        final String namespaceId = WebUtils//根据namespaceId获取命名空间,如果没有则为默认public
                .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
        final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);//根据serviceName获取服务名
        NamingUtils.checkServiceNameFormat(serviceName);//服务名格式为DEFAULT_GROUP@@nacos-test
        
        final Instance instance = HttpRequestInstanceBuilder.newBuilder()//根据当前请求创建临时实例
                .setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
        
        getInstanceOperator().registerInstance(namespaceId, serviceName, instance);//注册实例
        return "ok";
    }

这里是客户端请求会进入InstanceOperatorClientImpl

		boolean ephemeral = instance.isEphemeral();//判断是否是临时实例
        String clientId = IpPortBasedClient.getClientId(instance.toInetAddr(), ephemeral);//根据ip获取clientId——》127.0.0.1:8181#true
        createIpPortClientIfAbsent(clientId);//如果容器已有当前ip实例建立连接
        Service service = getService(namespaceId, serviceName, ephemeral);//创建服务实例
        clientOperationService.registerInstance(service, instance, clientId);//注册客户端实例
	@Override
    public void registerInstance(Service service, Instance instance, String clientId) {
        Service singleton = ServiceManager.getInstance().getSingleton(service);//获取服务单实例
        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));//发布事件
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值