• 【Nacos】源码之服务端服务注册


    Nacos客户端在启动时以及定时任务会发送Http请求,调用Nacos服务端接口/nacos/v1/ns/instance进行服务注册。

    我们根据url找到Nacos服务端服务注册的源码入口:

    com.alibaba.nacos.naming.controllers.InstanceController#register
    
    • 1

    InstanceController#register

    将请求封装为Instance,注意serviceName使用@@分隔组名和服务名,如DEFAULT_GROUP@@user,存入注册表中的serviceName也是包含组名的。

    com.alibaba.nacos.naming.controllers.InstanceController#register

    @CanDistro
    @PostMapping
    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
    public String register(HttpServletRequest request) throws Exception {
    	// 服务注册的入口
    	// 命名空间
    	final String namespaceId = WebUtils
    		.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
    	// 服务名称,使用@@分隔组名和服务名,如DEFAULT_GROUP@@user
    	final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
    	NamingUtils.checkServiceNameFormat(serviceName);
    
    	// 将请求包装为Instance,包含IP、端口、服务名、元数据等信息
    	// serviceName上面已获取,直接传入parseInstance()不好吗,parseInstance()里面又要去获取一次
    	final Instance instance = parseInstance(request);
    
    	serviceManager.registerInstance(namespaceId, serviceName, instance);
    	return "ok";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    ServiceManager#registerInstance

    创建一个空的Service放入serviceMap,将实例instance添加到服务service里面,注意这里只是更新到缓存中,还没改注册表。

    com.alibaba.nacos.naming.core.ServiceManager#registerInstance

    public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {
    
    	/**
             * Map(namespace, Map(group::serviceName, Service)).
             * 创建一个空的Service放入serviceMap
             */
    	createEmptyService(namespaceId, serviceName, instance.isEphemeral());
    
    	// 根据namespaceId和serviceName获得Service
    	// Service不是由createEmptyService()创建的吗,直接createEmptyService()返回Service岂不更好,省得这里又去查一次
    	Service service = getService(namespaceId, serviceName);
    
    	if (service == null) {
    		throw new NacosException(NacosException.INVALID_PARAM,
    								 "service not found, namespace: " + namespaceId + ", service: " + serviceName);
    	}
    
    	// 将实例instance添加到服务service里面
    	addInstance(namespaceId, serviceName, instance.isEphemeral(), instance);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    ServiceManager#createEmptyService

    如果服务不存在就创建一个。

    com.alibaba.nacos.naming.core.ServiceManager#createEmptyService

    public void createEmptyService(String namespaceId, String serviceName, boolean local) throws NacosException {
    	createServiceIfAbsent(namespaceId, serviceName, local, null);
    }
    
    public void createServiceIfAbsent(String namespaceId, String serviceName, boolean local, Cluster cluster)
    	throws NacosException {
    	Service service = getService(namespaceId, serviceName);
    	if (service == null) {
    
    		Loggers.SRV_LOG.info("creating empty service {}:{}", namespaceId, serviceName);
    		service = new Service();
    		service.setName(serviceName);
    		service.setNamespaceId(namespaceId);
    		service.setGroupName(NamingUtils.getGroupName(serviceName));
    		// now validate the service. if failed, exception will be thrown
    		service.setLastModifiedMillis(System.currentTimeMillis());
    		service.recalculateChecksum();
    		if (cluster != null) {
    			cluster.setService(service);
    			// cluster在这里创建
    			service.getClusterMap().put(cluster.getName(), cluster);
    		}
    		service.validate();
    
    		// 将service放入serviceMap,并初始化
    		putServiceAndInit(service);
    		if (!local) {
    			addOrReplaceService(service);
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    ServiceManager#putServiceAndInit

    将一个空的服务加入到注册表,并初始化服务,此时服务中并没有实例。

    com.alibaba.nacos.naming.core.ServiceManager#putServiceAndInit

    private void putServiceAndInit(Service service) throws NacosException {
    	// 将service放入serviceMap
    	putService(service);
    	service = getService(service.getNamespaceId(), service.getName());
    	// 开启客户端心跳检测任务
    	service.init();
    	/**
             * 哪里回调这些listener
             *
             * @see DistroConsistencyServiceImpl.Notifier#handle(org.javatuples.Pair)
             */
    	// 这里加入了两个listener
    	consistencyService
    		.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), true), service);
    	consistencyService
    		.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), false), service);
    	Loggers.SRV_LOG.info("[NEW-SERVICE] {}", service.toJson());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    ServiceManager#addInstance

    只是将新的实例与已有的实例进行合并,并放入缓存中。

    com.alibaba.nacos.naming.core.ServiceManager#addInstance

    public void addInstance(String namespaceId, String serviceName, boolean ephemeral, Instance... ips)
    	throws NacosException {
    
    	String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral);
    
    	// 又查了一次Service???
    	Service service = getService(namespaceId, serviceName);
    
    	synchronized (service) {
    		// 将缓存中的实例和注册中的实例合并得到instanceMap,最后将当前实例加入instanceMap
    		List<Instance> instanceList = addIpAddresses(service, ephemeral, ips);
    
    		Instances instances = new Instances();
    		instances.setInstanceList(instanceList);
    
    		// 将实例列表放入缓存中
    		/**
                 * @see DelegateConsistencyServiceImpl#put(String, Record)
                 */
    		consistencyService.put(key, instances);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ServiceManager#addIpAddresses

    新实例与旧实例列表合并的过程。

    com.alibaba.nacos.naming.core.ServiceManager#addIpAddresses

    private List<Instance> addIpAddresses(Service service, boolean ephemeral, Instance... ips) throws NacosException {
    	return updateIpAddresses(service, UtilsAndCommons.UPDATE_INSTANCE_ACTION_ADD, ephemeral, ips);
    }
    
    public List<Instance> updateIpAddresses(Service service, String action, boolean ephemeral, Instance... ips)
                throws NacosException {
    
    	// 从缓存中查询实例
    	Datum datum = consistencyService
    		.get(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), ephemeral));
    
    	// 从注册表中查询实例
    	List<Instance> currentIPs = service.allIPs(ephemeral);
    	// 
    	Map<String, Instance> currentInstances = new HashMap<>(currentIPs.size());
    	// 实例ID集合
    	Set<String> currentInstanceIds = Sets.newHashSet();
    
    	for (Instance instance : currentIPs) {
    		currentInstances.put(instance.toIpAddr(), instance);
    		currentInstanceIds.add(instance.getInstanceId());
    	}
    
    	// 合并缓存中的实例和注册表中的实例
    	Map<String, Instance> instanceMap;
    	if (datum != null && null != datum.value) {
    		instanceMap = setValid(((Instances) datum.value).getInstanceList(), currentInstances);
    	} else {
    		instanceMap = new HashMap<>(ips.length);
    	}
    
    	for (Instance instance : ips) {
    		if (!service.getClusterMap().containsKey(instance.getClusterName())) {
    			Cluster cluster = new Cluster(instance.getClusterName(), service);
    			cluster.init();
    			service.getClusterMap().put(instance.getClusterName(), cluster);
    			Loggers.SRV_LOG
    				.warn("cluster: {} not found, ip: {}, will create new cluster with default configuration.",
    					  instance.getClusterName(), instance.toJson());
    		}
    
    		if (UtilsAndCommons.UPDATE_INSTANCE_ACTION_REMOVE.equals(action)) {
    			// 从instanceMap中删除实例
    			instanceMap.remove(instance.getDatumKey());
    		} else {
    			// 将实例放入到instanceMap中
    			Instance oldInstance = instanceMap.get(instance.getDatumKey());
    			if (oldInstance != null) {
    				instance.setInstanceId(oldInstance.getInstanceId());
    			} else {
    				instance.setInstanceId(instance.generateInstanceId(currentInstanceIds));
    			}
    			instanceMap.put(instance.getDatumKey(), instance);
    		}
    
    	}
    
    	if (instanceMap.size() <= 0 && UtilsAndCommons.UPDATE_INSTANCE_ACTION_ADD.equals(action)) {
    		throw new IllegalArgumentException(
    			"ip list can not be empty, service: " + service.getName() + ", ip list: " + JacksonUtils
    			.toJson(instanceMap.values()));
    	}
    
    	// 将合并后的实例返回
    	return new ArrayList<>(instanceMap.values());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    DelegateConsistencyServiceImpl#put

    这里只是做一个代理,让不同的协议走不同的Service类。

    com.alibaba.nacos.naming.consistency.DelegateConsistencyServiceImpl#put

    public void put(String key, Record value) throws NacosException {
    	/**
             * ephemeral:true AP ephemeralConsistencyService,其实现类为DistroConsistencyServiceImpl
             * ephemeral:false CP persistentConsistencyService 单节点StandalonePersistentServiceProcessor,集群PersistentServiceProcessor
             *
             * @see DistroConsistencyServiceImpl#put(java.lang.String, com.alibaba.nacos.naming.pojo.Record)
             * @see com.alibaba.nacos.naming.consistency.persistent.impl.PersistentServiceProcessor#put(String, Record)
             * @see com.alibaba.nacos.naming.consistency.persistent.impl.StandalonePersistentServiceProcessor#put(String, Record)
             */
    	mapConsistencyService(key).put(key, value);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    DistroConsistencyServiceImpl#put

    默认使用的是AP协议,走的是DistroConsistencyServiceImpl。

    com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl#put

    public void put(String key, Record value) throws NacosException {
    	// 放入缓存,添加实例变更任务
    	onPut(key, value);
    
    	// 将实例变更同步给其他节点
    	distroProtocol.sync(new DistroKey(key, KeyBuilder.INSTANCE_LIST_KEY_PREFIX), DataOperation.CHANGE,
    						globalConfig.getTaskDispatchPeriod() / 2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    DistroConsistencyServiceImpl#onPut

    这里会将实例列表数据放入缓存中,然后添加一个实例变更的任务。
    com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl#onPut

    public void onPut(String key, Record value) {
    
    	// 放入缓存
    	if (KeyBuilder.matchEphemeralInstanceListKey(key)) {
    		Datum<Instances> datum = new Datum<>();
    		datum.value = (Instances) value;
    		datum.key = key;
    		datum.timestamp.incrementAndGet();
    		// 实例变更数据存dataStore
    		dataStore.put(key, datum);
    	}
    
    	if (!listeners.containsKey(key)) {
    		return;
    	}
    
    	// 添加实例变更的任务
    	notifier.addTask(key, DataOperation.CHANGE);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Notifier#addTask

    实例变更的任务最后添加到一个阻塞队列中,那么这个任务什么时候从阻塞队列中取出并执行呢?

    com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl.Notifier#addTask

    private BlockingQueue<Pair<String, DataOperation>> tasks = new ArrayBlockingQueue<>(1024 * 1024);
    
    /**
             * Add new notify task to queue.
             *
             * @param datumKey data key
             * @param action   action for data
             */
    public void addTask(String datumKey, DataOperation action) {
    
    	if (services.containsKey(datumKey) && action == DataOperation.CHANGE) {
    		return;
    	}
    	if (action == DataOperation.CHANGE) {
    		// 加入services,防止重复添加任务
    		services.put(datumKey, StringUtils.EMPTY);
    	}
    	/**
                 * 哪里取这些任务
                 *
                 * @see Notifier#run()
                 */
    	tasks.offer(Pair.with(datumKey, action));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    到这里整个实例的注册过程已完成,但是并没有看到instance放入到service中的过程,这个过程在下面的异步处理中。

    Notifier#run

    Notifier是DistroConsistencyServiceImpl的一个成员变量,在DistroConsistencyServiceImpl#init方法使用线程池来执行Notifier,所以Notifier肯定实现了Runable接口。

    com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl#init

        private volatile Notifier notifier = new Notifier();
    
        @PostConstruct
        public void init() {
            GlobalExecutor.submitDistroNotifyTask(notifier);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    那么我们来看看Notifier#run怎么执行的?从阻塞队列中一个一个的取出并处理。

    com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl.Notifier#run

    @Override
    public void run() {
    	Loggers.DISTRO.info("distro notifier started");
    
    	for (; ; ) {
    		try {
    			// 阻塞队伍中获取
    			Pair<String, DataOperation> pair = tasks.take();
    			// 处理实例变更
    			handle(pair);
    		} catch (Throwable e) {
    			Loggers.DISTRO.error("[NACOS-DISTRO] Error while handling notifying task", e);
    		}
    	}
    }
    
    private void handle(Pair<String, DataOperation> pair) {
    	try {
    		String datumKey = pair.getValue0();
    		DataOperation action = pair.getValue1();
    
    		services.remove(datumKey);
    
    		int count = 0;
    
    		if (!listeners.containsKey(datumKey)) {
    			return;
    		}
    
    		for (RecordListener listener : listeners.get(datumKey)) {
    
    			count++;
    
    			try {
    				if (action == DataOperation.CHANGE) {
    					// 处理变更
    					// 根据datumKey从dataStore获取实例变更的数据
    					/**
                                 * @see com.alibaba.nacos.naming.core.Service#onChange(java.lang.String, com.alibaba.nacos.naming.core.Instances)
                                 */
    					listener.onChange(datumKey, dataStore.get(datumKey).value);
    					continue;
    				}
    
    				if (action == DataOperation.DELETE) {
    					// 处理删除
    					listener.onDelete(datumKey);
    					continue;
    				}
    			} catch (Throwable e) {
    				Loggers.DISTRO.error("[NACOS-DISTRO] error while notifying listener of key: {}", datumKey, e);
    			}
    		}
    
    		if (Loggers.DISTRO.isDebugEnabled()) {
    			Loggers.DISTRO
    				.debug("[NACOS-DISTRO] datum change notified, key: {}, listener count: {}, action: {}",
    					   datumKey, count, action.name());
    		}
    	} catch (Throwable e) {
    		Loggers.DISTRO.error("[NACOS-DISTRO] Error while handling notifying task", e);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    Service#onChange

    com.alibaba.nacos.naming.core.Service#onChange

    public void onChange(String key, Instances value) throws Exception {
    
    	Loggers.SRV_LOG.info("[NACOS-RAFT] datum is changed, key: {}, value: {}", key, value);
    
    	for (Instance instance : value.getInstanceList()) {
    
    		if (instance == null) {
    			// Reject this abnormal instance list:
    			throw new RuntimeException("got null instance " + key);
    		}
    
    		if (instance.getWeight() > 10000.0D) {
    			instance.setWeight(10000.0D);
    		}
    
    		if (instance.getWeight() < 0.01D && instance.getWeight() > 0.0D) {
    			instance.setWeight(0.01D);
    		}
    	}
    
    	// 真正的更新注册表
    	updateIPs(value.getInstanceList(), KeyBuilder.matchEphemeralInstanceListKey(key));
    
    	recalculateChecksum();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    Service#updateIPs

    将缓存中获取的实例列表按clusterName进行分组,最后以cluster为维度进行更新注册表。

    com.alibaba.nacos.naming.core.Service#updateIPs

    public void updateIPs(Collection<Instance> instances, boolean ephemeral) {
    	// 将instances按clusterName进行分组
    	Map<String, List<Instance>> ipMap = new HashMap<>(clusterMap.size());
    	for (String clusterName : clusterMap.keySet()) {
    		ipMap.put(clusterName, new ArrayList<>());
    	}
    
    	for (Instance instance : instances) {
    		try {
    			if (instance == null) {
    				Loggers.SRV_LOG.error("[NACOS-DOM] received malformed ip: null");
    				continue;
    			}
    
    			if (StringUtils.isEmpty(instance.getClusterName())) {
    				instance.setClusterName(UtilsAndCommons.DEFAULT_CLUSTER_NAME);
    			}
    
    			if (!clusterMap.containsKey(instance.getClusterName())) {
    				Loggers.SRV_LOG
    					.warn("cluster: {} not found, ip: {}, will create new cluster with default configuration.",
    						  instance.getClusterName(), instance.toJson());
    				Cluster cluster = new Cluster(instance.getClusterName(), this);
    				cluster.init();
    				getClusterMap().put(instance.getClusterName(), cluster);
    			}
    
    			List<Instance> clusterIPs = ipMap.get(instance.getClusterName());
    			if (clusterIPs == null) {
    				clusterIPs = new LinkedList<>();
    				ipMap.put(instance.getClusterName(), clusterIPs);
    			}
    
    			clusterIPs.add(instance);
    		} catch (Exception e) {
    			Loggers.SRV_LOG.error("[NACOS-DOM] failed to process ip: " + instance, e);
    		}
    	}
    
    	// 按clusterName进行遍历
    	for (Map.Entry<String, List<Instance>> entry : ipMap.entrySet()) {
    		//make every ip mine
    		List<Instance> entryIPs = entry.getValue();
    		// 更新IP
    		clusterMap.get(entry.getKey()).updateIps(entryIPs, ephemeral);
    	}
    
    	setLastModifiedMillis(System.currentTimeMillis());
    	getPushService().serviceChanged(this);
    	StringBuilder stringBuilder = new StringBuilder();
    
    	for (Instance instance : allIPs()) {
    		stringBuilder.append(instance.toIpAddr()).append("_").append(instance.isHealthy()).append(",");
    	}
    
    	Loggers.EVT_LOG.info("[IP-UPDATED] namespace: {}, service: {}, ips: {}", getNamespaceId(), getName(),
    						 stringBuilder.toString());
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    Cluster#updateIps

    com.alibaba.nacos.naming.core.Cluster#updateIps

    public void updateIps(List<Instance> ips, boolean ephemeral) {
    
    	Set<Instance> toUpdateInstances = ephemeral ? ephemeralInstances : persistentInstances;
    
    	HashMap<String, Instance> oldIpMap = new HashMap<>(toUpdateInstances.size());
    
    	for (Instance ip : toUpdateInstances) {
    		oldIpMap.put(ip.getDatumKey(), ip);
    	}
    
    	// 中间一大串只是为了识别出哪些是修改的、新增的、删除的,然后修改实例的健康状态
    	List<Instance> updatedIPs = updatedIps(ips, oldIpMap.values());
    	if (updatedIPs.size() > 0) {
    		for (Instance ip : updatedIPs) {
    			Instance oldIP = oldIpMap.get(ip.getDatumKey());
    
    			// do not update the ip validation status of updated ips
    			// because the checker has the most precise result
    			// Only when ip is not marked, don't we update the health status of IP:
    			if (!ip.isMarked()) {
    				ip.setHealthy(oldIP.isHealthy());
    			}
    
    			if (ip.isHealthy() != oldIP.isHealthy()) {
    				// ip validation status updated
    				Loggers.EVT_LOG.info("{} {SYNC} IP-{} {}:{}@{}", getService().getName(),
    									 (ip.isHealthy() ? "ENABLED" : "DISABLED"), ip.getIp(), ip.getPort(), getName());
    			}
    
    			if (ip.getWeight() != oldIP.getWeight()) {
    				// ip validation status updated
    				Loggers.EVT_LOG.info("{} {SYNC} {IP-UPDATED} {}->{}", getService().getName(), oldIP.toString(),
    									 ip.toString());
    			}
    		}
    	}
    
    	List<Instance> newIPs = subtract(ips, oldIpMap.values());
    	if (newIPs.size() > 0) {
    		Loggers.EVT_LOG
    			.info("{} {SYNC} {IP-NEW} cluster: {}, new ips size: {}, content: {}", getService().getName(),
    				  getName(), newIPs.size(), newIPs.toString());
    
    		for (Instance ip : newIPs) {
    			HealthCheckStatus.reset(ip);
    		}
    	}
    
    	List<Instance> deadIPs = subtract(oldIpMap.values(), ips);
    
    	if (deadIPs.size() > 0) {
    		Loggers.EVT_LOG
    			.info("{} {SYNC} {IP-DEAD} cluster: {}, dead ips size: {}, content: {}", getService().getName(),
    				  getName(), deadIPs.size(), deadIPs.toString());
    
    		for (Instance ip : deadIPs) {
    			HealthCheckStatus.remv(ip);
    		}
    	}
    
    	toUpdateInstances = new HashSet<>(ips);
    
    	// 直接覆盖原来的引用,CopyOnWrite
    	if (ephemeral) {
    		ephemeralInstances = toUpdateInstances;
    	} else {
    		persistentInstances = toUpdateInstances;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    服务端怎么保证注册表的高并发读和写?

    1. 注册表的写是异步的,而且是通过一个任务来执行,这样保证只有一个线程进行写,不会有并发。
    2. 写注册表时是使用新的对象直接覆盖原来的引用,类似CopyOnWrite机制,不影响读。
  • 相关阅读:
    Vue3 动态组件 component:is= 失效
    【畅购商城】详情页详情之商品详情
    微信小程序 加载 fbx 模型
    HTML期末学生大作业 基于HTML+CSS+JavaScript通用的后台管理系统ui框架模板
    const和volatile和restict
    Pyramid 中的wtforms中的SelectField和通过javascript添加标签选项
    【Qt秘籍】[005]-Qt的首次邂逅-创建
    30天精通Python(数据分析篇)——第2天:环境搭建之Windows下安装Anaconda及使用介绍
    uniapp Map 计算实时定位到达某个具体位置距离 及 在uniappMap上绘制浮框
    vue3中el-tree的使用及后端传参
  • 原文地址:https://blog.csdn.net/u022812849/article/details/128187321