From 488ae6a2511a68b7323cd5d0a5955dd18743b91c Mon Sep 17 00:00:00 2001 From: pengzhengfa <13656694002@163.com> Date: Wed, 17 Jun 2020 16:24:02 +0800 Subject: [PATCH 1/6] Instance eliminate module naming optimization --- .../com/alibaba/nacos/naming/core/Cluster.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java b/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java index 9c8037b63f9..e0eea6c9a72 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java @@ -300,21 +300,21 @@ public List updatedIPs(Collection a, Collection b) return new ArrayList<>(instanceMap.values()); } - public List subtract(Collection a, Collection b) { - Map mapa = new HashMap<>(b.size()); - for (Instance o : b) { - mapa.put(o.getIp() + ":" + o.getPort(), o); + public List subtract(Collection oldIp, Collection ips) { + Map IpsMap = new HashMap<>(ips.size()); + for (Instance instance : ips) { + IpsMap.put(instance.getIp() + ":" + instance.getPort(), instance); } - List result = new ArrayList<>(); + List instanceResult = new ArrayList<>(); - for (Instance o : a) { - if (!mapa.containsKey(o.getIp() + ":" + o.getPort())) { - result.add(o); + for (Instance instance : oldIp) { + if (!IpsMap.containsKey(instance.getIp() + ":" + instance.getPort())) { + instanceResult.add(instance); } } - return result; + return instanceResult; } @Override From 501bc80bc7e8427cb6557256ae09bb2aa6f47709 Mon Sep 17 00:00:00 2001 From: pengzhengfa <13656694002@163.com> Date: Wed, 17 Jun 2020 17:58:25 +0800 Subject: [PATCH 2/6] Solve PMD check failed --- .../main/java/com/alibaba/nacos/naming/core/Cluster.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java b/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java index e0eea6c9a72..cd066dac5ed 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java @@ -301,15 +301,15 @@ public List updatedIPs(Collection a, Collection b) } public List subtract(Collection oldIp, Collection ips) { - Map IpsMap = new HashMap<>(ips.size()); + Map ipsMap = new HashMap<>(ips.size()); for (Instance instance : ips) { - IpsMap.put(instance.getIp() + ":" + instance.getPort(), instance); + ipsMap.put(instance.getIp() + ":" + instance.getPort(), instance); } List instanceResult = new ArrayList<>(); for (Instance instance : oldIp) { - if (!IpsMap.containsKey(instance.getIp() + ":" + instance.getPort())) { + if (!ipsMap.containsKey(instance.getIp() + ":" + instance.getPort())) { instanceResult.add(instance); } } From cb802e3ef969f13db5a8581b205102d01d392480 Mon Sep 17 00:00:00 2001 From: pengzhengfa <13656694002@163.com> Date: Thu, 18 Jun 2020 10:12:14 +0800 Subject: [PATCH 3/6] Method name optimization --- .../consistency/ConsistencyService.java | 14 +- .../DelegateConsistencyServiceImpl.java | 28 +- .../distro/DistroConsistencyServiceImpl.java | 152 +++--- .../raft/RaftConsistencyServiceImpl.java | 26 +- .../consistency/persistent/raft/RaftCore.java | 450 +++++++++--------- .../controllers/InstanceController.java | 202 ++++---- .../alibaba/nacos/naming/core/Cluster.java | 156 +++--- .../nacos/naming/core/ServiceManager.java | 366 +++++++------- 8 files changed, 697 insertions(+), 697 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/ConsistencyService.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/ConsistencyService.java index 76f9a41ad33..ae4519839fc 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/ConsistencyService.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/ConsistencyService.java @@ -32,7 +32,7 @@ * @since 1.0.0 */ public interface ConsistencyService { - + /** * Put a data related to a key to Nacos cluster. * @@ -41,7 +41,7 @@ public interface ConsistencyService { * @throws NacosException nacos exception */ void put(String key, Record value) throws NacosException; - + /** * Remove a data from Nacos cluster. * @@ -49,7 +49,7 @@ public interface ConsistencyService { * @throws NacosException nacos exception */ void remove(String key) throws NacosException; - + /** * Get a data from Nacos cluster. * @@ -58,7 +58,7 @@ public interface ConsistencyService { * @throws NacosException nacos exception */ Datum get(String key) throws NacosException; - + /** * Listen for changes of a data. * @@ -67,7 +67,7 @@ public interface ConsistencyService { * @throws NacosException nacos exception */ void listen(String key, RecordListener listener) throws NacosException; - + /** * Cancel listening of a data. * @@ -75,8 +75,8 @@ public interface ConsistencyService { * @param listener callback of data change * @throws NacosException nacos exception */ - void unlisten(String key, RecordListener listener) throws NacosException; - + void unListen(String key, RecordListener listener) throws NacosException; + /** * Tell the status of this consistency service. * diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/DelegateConsistencyServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/DelegateConsistencyServiceImpl.java index 4e3d059cefe..bae2f76dc67 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/DelegateConsistencyServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/DelegateConsistencyServiceImpl.java @@ -32,55 +32,55 @@ @DependsOn("ProtocolManager") @Service("consistencyDelegate") public class DelegateConsistencyServiceImpl implements ConsistencyService { - + private final PersistentConsistencyService persistentConsistencyService; - + private final EphemeralConsistencyService ephemeralConsistencyService; - + public DelegateConsistencyServiceImpl(PersistentConsistencyService persistentConsistencyService, EphemeralConsistencyService ephemeralConsistencyService) { this.persistentConsistencyService = persistentConsistencyService; this.ephemeralConsistencyService = ephemeralConsistencyService; } - + @Override public void put(String key, Record value) throws NacosException { mapConsistencyService(key).put(key, value); } - + @Override public void remove(String key) throws NacosException { mapConsistencyService(key).remove(key); } - + @Override public Datum get(String key) throws NacosException { return mapConsistencyService(key).get(key); } - + @Override public void listen(String key, RecordListener listener) throws NacosException { - + // this special key is listened by both: if (KeyBuilder.SERVICE_META_KEY_PREFIX.equals(key)) { persistentConsistencyService.listen(key, listener); ephemeralConsistencyService.listen(key, listener); return; } - + mapConsistencyService(key).listen(key, listener); } - + @Override - public void unlisten(String key, RecordListener listener) throws NacosException { - mapConsistencyService(key).unlisten(key, listener); + public void unListen(String key, RecordListener listener) throws NacosException { + mapConsistencyService(key).unListen(key, listener); } - + @Override public boolean isAvailable() { return ephemeralConsistencyService.isAvailable() && persistentConsistencyService.isAvailable(); } - + private ConsistencyService mapConsistencyService(String key) { return KeyBuilder.matchEphemeralKey(key) ? ephemeralConsistencyService : persistentConsistencyService; } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/DistroConsistencyServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/DistroConsistencyServiceImpl.java index 51508ff5f3f..29c60b4712b 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/DistroConsistencyServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/DistroConsistencyServiceImpl.java @@ -67,31 +67,31 @@ @DependsOn("ProtocolManager") @org.springframework.stereotype.Service("distroConsistencyService") public class DistroConsistencyServiceImpl implements EphemeralConsistencyService { - + private final DistroMapper distroMapper; - + private final DataStore dataStore; - + private final TaskDispatcher taskDispatcher; - + private final Serializer serializer; - + private final ServerMemberManager memberManager; - + private final SwitchDomain switchDomain; - + private final GlobalConfig globalConfig; - + private boolean initialized = false; - + private volatile Notifier notifier = new Notifier(); - + private LoadDataTask loadDataTask = new LoadDataTask(); - + private Map> listeners = new ConcurrentHashMap<>(); - + private Map syncChecksumTasks = new ConcurrentHashMap<>(16); - + public DistroConsistencyServiceImpl(DistroMapper distroMapper, DataStore dataStore, TaskDispatcher taskDispatcher, Serializer serializer, ServerMemberManager memberManager, SwitchDomain switchDomain, GlobalConfig globalConfig) { @@ -103,15 +103,15 @@ public DistroConsistencyServiceImpl(DistroMapper distroMapper, DataStore dataSto this.switchDomain = switchDomain; this.globalConfig = globalConfig; } - + @PostConstruct public void init() { GlobalExecutor.submit(loadDataTask); GlobalExecutor.submitDistroNotifyTask(notifier); } - + private class LoadDataTask implements Runnable { - + @Override public void run() { try { @@ -126,7 +126,7 @@ public void run() { } } } - + private void load() throws Exception { if (ApplicationUtils.getStandaloneMode()) { initialized = true; @@ -137,7 +137,7 @@ private void load() throws Exception { Thread.sleep(1000L); Loggers.DISTRO.info("waiting server list init..."); } - + for (Map.Entry entry : memberManager.getServerList().entrySet()) { final String address = entry.getValue().getAddress(); if (ApplicationUtils.getLocalAddress().equals(address)) { @@ -153,24 +153,24 @@ private void load() throws Exception { } } } - + @Override public void put(String key, Record value) throws NacosException { onPut(key, value); taskDispatcher.addTask(key); } - + @Override public void remove(String key) throws NacosException { onRemove(key); listeners.remove(key); } - + @Override public Datum get(String key) throws NacosException { return dataStore.get(key); } - + /** * Put a new record. * @@ -178,7 +178,7 @@ public Datum get(String key) throws NacosException { * @param value record */ public void onPut(String key, Record value) { - + if (KeyBuilder.matchEphemeralInstanceListKey(key)) { Datum datum = new Datum<>(); datum.value = (Instances) value; @@ -186,30 +186,30 @@ public void onPut(String key, Record value) { datum.timestamp.incrementAndGet(); dataStore.put(key, datum); } - + if (!listeners.containsKey(key)) { return; } - + notifier.addTask(key, ApplyAction.CHANGE); } - + /** * Remove a record. * * @param key key of record */ public void onRemove(String key) { - + dataStore.remove(key); - + if (!listeners.containsKey(key)) { return; } - + notifier.addTask(key, ApplyAction.DELETE); } - + /** * Check sum when receive checksums request. * @@ -217,17 +217,17 @@ public void onRemove(String key) { * @param server source server request checksum */ public void onReceiveChecksums(Map checksumMap, String server) { - + if (syncChecksumTasks.containsKey(server)) { // Already in process of this server: Loggers.DISTRO.warn("sync checksum task already in process with {}", server); return; } - + syncChecksumTasks.put(server, "1"); - + try { - + List toUpdateKeys = new ArrayList<>(); List toRemoveKeys = new ArrayList<>(); for (Map.Entry entry : checksumMap.entrySet()) { @@ -237,35 +237,35 @@ public void onReceiveChecksums(Map checksumMap, String server) { // abort the procedure: return; } - + if (!dataStore.contains(entry.getKey()) || dataStore.get(entry.getKey()).value == null || !dataStore .get(entry.getKey()).value.getChecksum().equals(entry.getValue())) { toUpdateKeys.add(entry.getKey()); } } - + for (String key : dataStore.keys()) { - + if (!server.equals(distroMapper.mapSrv(KeyBuilder.getServiceName(key)))) { continue; } - + if (!checksumMap.containsKey(key)) { toRemoveKeys.add(key); } } - + Loggers.DISTRO .info("to remove keys: {}, to update keys: {}, source: {}", toRemoveKeys, toUpdateKeys, server); - + for (String key : toRemoveKeys) { onRemove(key); } - + if (toUpdateKeys.isEmpty()) { return; } - + try { byte[] result = NamingProxy.getData(toUpdateKeys, server); processData(result); @@ -277,9 +277,9 @@ public void onReceiveChecksums(Map checksumMap, String server) { syncChecksumTasks.remove(server); } } - + private boolean syncAllDataFromRemote(String server) { - + try { byte[] data = NamingProxy.getAllData(server); return processData(data); @@ -288,14 +288,14 @@ private boolean syncAllDataFromRemote(String server) { return false; } } - + private boolean processData(byte[] data) throws Exception { if (data.length > 0) { Map> datumMap = serializer.deserializeMap(data, Instances.class); - + for (Map.Entry> entry : datumMap.entrySet()) { dataStore.put(entry.getKey(), entry.getValue()); - + if (!listeners.containsKey(entry.getKey())) { // pretty sure the service not exist: if (switchDomain.isDefaultInstanceEphemeral()) { @@ -310,7 +310,7 @@ private boolean processData(byte[] data) throws Exception { // now validate the service. if failed, exception will be thrown service.setLastModifiedMillis(System.currentTimeMillis()); service.recalculateChecksum(); - + // The Listener corresponding to the key value must not be empty RecordListener listener = listeners.get(KeyBuilder.SERVICE_META_KEY_PREFIX).peek(); if (Objects.isNull(listener)) { @@ -320,15 +320,15 @@ private boolean processData(byte[] data) throws Exception { } } } - + for (Map.Entry> entry : datumMap.entrySet()) { - + if (!listeners.containsKey(entry.getKey())) { // Should not happen: Loggers.DISTRO.warn("listener of {} not found.", entry.getKey()); continue; } - + try { for (RecordListener listener : listeners.get(entry.getKey())) { listener.onChange(entry.getKey(), entry.getValue().value); @@ -337,29 +337,29 @@ private boolean processData(byte[] data) throws Exception { Loggers.DISTRO.error("[NACOS-DISTRO] error while execute listener of key: {}", entry.getKey(), e); continue; } - + // Update data store if listener executed successfully: dataStore.put(entry.getKey(), entry.getValue()); } } return true; } - + @Override public void listen(String key, RecordListener listener) throws NacosException { if (!listeners.containsKey(key)) { listeners.put(key, new ConcurrentLinkedQueue<>()); } - + if (listeners.get(key).contains(listener)) { return; } - + listeners.get(key).add(listener); } - + @Override - public void unlisten(String key, RecordListener listener) throws NacosException { + public void unListen(String key, RecordListener listener) throws NacosException { if (!listeners.containsKey(key)) { return; } @@ -370,22 +370,22 @@ public void unlisten(String key, RecordListener listener) throws NacosException } } } - + @Override public boolean isAvailable() { return isInitialized() || ServerStatus.UP.name().equals(switchDomain.getOverriddenServerStatus()); } - + public boolean isInitialized() { return initialized || !globalConfig.isDataWarmup(); } - + public class Notifier implements Runnable { - + private ConcurrentHashMap services = new ConcurrentHashMap<>(10 * 1024); - + private BlockingQueue> tasks = new ArrayBlockingQueue<>(1024 * 1024); - + /** * Add new notify task to queue. * @@ -393,7 +393,7 @@ public class Notifier implements Runnable { * @param action action for data */ public void addTask(String datumKey, ApplyAction action) { - + if (services.containsKey(datumKey) && action == ApplyAction.CHANGE) { return; } @@ -402,15 +402,15 @@ public void addTask(String datumKey, ApplyAction action) { } tasks.offer(Pair.with(datumKey, action)); } - + public int getTaskSize() { return tasks.size(); } - + @Override public void run() { Loggers.DISTRO.info("distro notifier started"); - + for (; ; ) { try { Pair pair = tasks.take(); @@ -420,30 +420,30 @@ public void run() { } } } - + private void handle(Pair pair) { try { String datumKey = pair.getValue0(); ApplyAction action = pair.getValue1(); - + services.remove(datumKey); - + int count = 0; - + if (!listeners.containsKey(datumKey)) { return; } - + for (RecordListener listener : listeners.get(datumKey)) { - + count++; - + try { if (action == ApplyAction.CHANGE) { listener.onChange(datumKey, dataStore.get(datumKey).value); continue; } - + if (action == ApplyAction.DELETE) { listener.onDelete(datumKey); continue; @@ -452,7 +452,7 @@ private void handle(Pair pair) { 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: {}", diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java index 8ce6ff0f3e9..b0442add46b 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java @@ -38,16 +38,16 @@ @DependsOn("ProtocolManager") @Service public class RaftConsistencyServiceImpl implements PersistentConsistencyService { - + @Autowired private RaftCore raftCore; - + @Autowired private RaftPeerSet peers; - + @Autowired private SwitchDomain switchDomain; - + @Override public void put(String key, Record value) throws NacosException { try { @@ -58,7 +58,7 @@ public void put(String key, Record value) throws NacosException { e); } } - + @Override public void remove(String key) throws NacosException { try { @@ -76,27 +76,27 @@ public void remove(String key) throws NacosException { throw new NacosException(NacosException.SERVER_ERROR, "Raft remove failed, key:" + key, e); } } - + @Override public Datum get(String key) throws NacosException { return raftCore.getDatum(key); } - + @Override public void listen(String key, RecordListener listener) throws NacosException { raftCore.listen(key, listener); } - + @Override - public void unlisten(String key, RecordListener listener) throws NacosException { - raftCore.unlisten(key, listener); + public void unListen(String key, RecordListener listener) throws NacosException { + raftCore.unListen(key, listener); } - + @Override public boolean isAvailable() { return raftCore.isInitialized() || ServerStatus.UP.name().equals(switchDomain.getOverriddenServerStatus()); } - + /** * Put a new datum from other server. * @@ -113,7 +113,7 @@ public void onPut(Datum datum, RaftPeer source) throws NacosException { "Raft onPut failed, datum:" + datum + ", source: " + source, e); } } - + /** * Remove a new datum from other server. * diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java index 7ec7f8fa9b9..b38dea638d1 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java @@ -82,62 +82,62 @@ @DependsOn("ProtocolManager") @Component public class RaftCore { - + public static final String API_VOTE = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/vote"; - + public static final String API_BEAT = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/beat"; - + public static final String API_PUB = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/datum"; - + public static final String API_DEL = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/datum"; - + public static final String API_GET = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/datum"; - + public static final String API_ON_PUB = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/datum/commit"; - + public static final String API_ON_DEL = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/datum/commit"; - + public static final String API_GET_PEER = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/peer"; - + private final ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1, new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); - + t.setDaemon(true); t.setName("com.alibaba.nacos.naming.raft.notifier"); - + return t; } }); - + public static final Lock OPERATE_LOCK = new ReentrantLock(); - + public static final int PUBLISH_TERM_INCREASE_COUNT = 100; - + private volatile ConcurrentMap> listeners = new ConcurrentHashMap<>(); - + private volatile ConcurrentMap datums = new ConcurrentHashMap<>(); - + @Autowired private RaftPeerSet peers; - + @Autowired private SwitchDomain switchDomain; - + @Autowired private GlobalConfig globalConfig; - + @Autowired private RaftProxy raftProxy; - + @Autowired private RaftStore raftStore; - + public volatile Notifier notifier = new Notifier(); - + private boolean initialized = false; - + /** * Init raft core. * @@ -145,41 +145,41 @@ public Thread newThread(Runnable r) { */ @PostConstruct public void init() throws Exception { - + Loggers.RAFT.info("initializing Raft sub-system"); - + executor.submit(notifier); - + final long start = System.currentTimeMillis(); - + raftStore.loadDatums(notifier, datums); - + setTerm(NumberUtils.toLong(raftStore.loadMeta().getProperty("term"), 0L)); - + Loggers.RAFT.info("cache loaded, datum count: {}, current term: {}", datums.size(), peers.getTerm()); - + while (true) { if (notifier.tasks.size() <= 0) { break; } Thread.sleep(1000L); } - + initialized = true; - + Loggers.RAFT.info("finish to load data from disk, cost: {} ms.", (System.currentTimeMillis() - start)); - + GlobalExecutor.registerMasterElection(new MasterElection()); GlobalExecutor.registerHeartbeat(new HeartBeat()); - + Loggers.RAFT.info("timer started: leader timeout ms: {}, heart-beat timeout ms: {}", GlobalExecutor.LEADER_TIMEOUT_MS, GlobalExecutor.HEARTBEAT_INTERVAL_MS); } - + public Map> getListeners() { return listeners; } - + /** * Signal publish new record. If not leader, signal to leader. If leader, try to commit publish. * @@ -188,20 +188,20 @@ public Map> getListeners() { * @throws Exception any exception during publish */ public void signalPublish(String key, Record value) throws Exception { - + if (!isLeader()) { ObjectNode params = JacksonUtils.createEmptyJsonNode(); params.put("key", key); params.replace("value", JacksonUtils.transferToJsonNode(value)); Map parameters = new HashMap<>(1); parameters.put("key", key); - + final RaftPeer leader = getLeader(); - + raftProxy.proxyPostLarge(leader.ip, API_PUB, params.toString(), parameters); return; } - + try { OPERATE_LOCK.lock(); final long start = System.currentTimeMillis(); @@ -213,15 +213,15 @@ public void signalPublish(String key, Record value) throws Exception { } else { datum.timestamp.set(getDatum(key).timestamp.incrementAndGet()); } - + ObjectNode json = JacksonUtils.createEmptyJsonNode(); json.replace("datum", JacksonUtils.transferToJsonNode(datum)); json.replace("source", JacksonUtils.transferToJsonNode(peers.local())); - + onPublish(datum, peers.local()); - + final String content = json.toString(); - + final CountDownLatch latch = new CountDownLatch(peers.majorityCount()); for (final String server : peers.allServersIncludeMyself()) { if (isLeader(server)) { @@ -242,28 +242,28 @@ public Integer onCompleted(Response response) throws Exception { latch.countDown(); return 0; } - + @Override public STATE onContentWriteCompleted() { return STATE.CONTINUE; } }); - + } - + if (!latch.await(UtilsAndCommons.RAFT_PUBLISH_TIMEOUT, TimeUnit.MILLISECONDS)) { // only majority servers return success can we consider this update success Loggers.RAFT.error("data publish failed, caused failed to notify majority, key={}", key); throw new IllegalStateException("data publish failed, caused failed to notify majority, key=" + key); } - + long end = System.currentTimeMillis(); Loggers.RAFT.info("signalPublish cost {} ms, key: {}", (end - start), key); } finally { OPERATE_LOCK.unlock(); } } - + /** * Signal delete record. If not leader, signal leader delete. If leader, try to commit delete. * @@ -271,26 +271,26 @@ public STATE onContentWriteCompleted() { * @throws Exception any exception during delete */ public void signalDelete(final String key) throws Exception { - + OPERATE_LOCK.lock(); try { - + if (!isLeader()) { Map params = new HashMap<>(1); params.put("key", URLEncoder.encode(key, "UTF-8")); raftProxy.proxy(getLeader().ip, API_DEL, params, HttpMethod.DELETE); return; } - + // construct datum: Datum datum = new Datum(); datum.key = key; ObjectNode json = JacksonUtils.createEmptyJsonNode(); json.replace("datum", JacksonUtils.transferToJsonNode(datum)); json.replace("source", JacksonUtils.transferToJsonNode(peers.local())); - + onDelete(datum.key, peers.local()); - + for (final String server : peers.allServersWithoutMySelf()) { String url = buildUrl(server, API_ON_DEL); HttpClient.asyncHttpDeleteLarge(url, null, json.toString(), new AsyncCompletionHandler() { @@ -302,11 +302,11 @@ public Integer onCompleted(Response response) throws Exception { key, server, response.getStatusCode()); return 1; } - + RaftPeer local = peers.local(); - + local.resetLeaderDue(); - + return 0; } }); @@ -315,7 +315,7 @@ public Integer onCompleted(Response response) throws Exception { OPERATE_LOCK.unlock(); } } - + /** * Do publish. If leader, commit publish to store. If not leader, stop publish because should signal to leader. * @@ -329,30 +329,30 @@ public void onPublish(Datum datum, RaftPeer source) throws Exception { Loggers.RAFT.warn("received empty datum"); throw new IllegalStateException("received empty datum"); } - + if (!peers.isLeader(source.ip)) { Loggers.RAFT .warn("peer {} tried to publish data but wasn't leader, leader: {}", JacksonUtils.toJson(source), JacksonUtils.toJson(getLeader())); throw new IllegalStateException("peer(" + source.ip + ") tried to publish " + "data but wasn't leader"); } - + if (source.term.get() < local.term.get()) { Loggers.RAFT.warn("out of date publish, pub-term: {}, cur-term: {}", JacksonUtils.toJson(source), JacksonUtils.toJson(local)); throw new IllegalStateException( "out of date publish, pub-term:" + source.term.get() + ", cur-term: " + local.term.get()); } - + local.resetLeaderDue(); - + // if data should be persisted, usually this is true: if (KeyBuilder.matchPersistentKey(datum.key)) { raftStore.write(datum); } - + datums.put(datum.key, datum); - + if (isLeader()) { local.term.addAndGet(PUBLISH_TERM_INCREASE_COUNT); } else { @@ -365,12 +365,12 @@ public void onPublish(Datum datum, RaftPeer source) throws Exception { } } raftStore.updateTerm(local.term.get()); - + notifier.addTask(datum.key, ApplyAction.CHANGE); - + Loggers.RAFT.info("data added/updated, key={}, term={}", datum.key, local.term); } - + /** * Do delete. If leader, commit delete to store. If not leader, stop delete because should signal to leader. * @@ -379,31 +379,31 @@ public void onPublish(Datum datum, RaftPeer source) throws Exception { * @throws Exception any exception during delete */ public void onDelete(String datumKey, RaftPeer source) throws Exception { - + RaftPeer local = peers.local(); - + if (!peers.isLeader(source.ip)) { Loggers.RAFT .warn("peer {} tried to publish data but wasn't leader, leader: {}", JacksonUtils.toJson(source), JacksonUtils.toJson(getLeader())); throw new IllegalStateException("peer(" + source.ip + ") tried to publish data but wasn't leader"); } - + if (source.term.get() < local.term.get()) { Loggers.RAFT.warn("out of date publish, pub-term: {}, cur-term: {}", JacksonUtils.toJson(source), JacksonUtils.toJson(local)); throw new IllegalStateException( "out of date publish, pub-term:" + source.term + ", cur-term: " + local.term); } - + local.resetLeaderDue(); - + // do apply String key = datumKey; deleteDatum(key); - + if (KeyBuilder.matchServiceMetaKey(key)) { - + if (local.term.get() + PUBLISH_TERM_INCREASE_COUNT > source.term.get()) { //set leader term: getLeader().term.set(source.term.get()); @@ -411,54 +411,54 @@ public void onDelete(String datumKey, RaftPeer source) throws Exception { } else { local.term.addAndGet(PUBLISH_TERM_INCREASE_COUNT); } - + raftStore.updateTerm(local.term.get()); } - + Loggers.RAFT.info("data removed, key={}, term={}", datumKey, local.term); - + } - + public class MasterElection implements Runnable { - + @Override public void run() { try { - + if (!peers.isReady()) { return; } - + RaftPeer local = peers.local(); local.leaderDueMs -= GlobalExecutor.TICK_PERIOD_MS; - + if (local.leaderDueMs > 0) { return; } - + // reset timeout local.resetLeaderDue(); local.resetHeartbeatDue(); - + sendVote(); } catch (Exception e) { Loggers.RAFT.warn("[RAFT] error while master election {}", e); } - + } - + private void sendVote() { - + RaftPeer local = peers.get(NetUtils.localServer()); Loggers.RAFT.info("leader timeout, start voting,leader: {}, term: {}", JacksonUtils.toJson(getLeader()), local.term); - + peers.reset(); - + local.term.incrementAndGet(); local.voteFor = local.ip; local.state = RaftPeer.State.CANDIDATE; - + Map params = new HashMap<>(1); params.put("vote", JacksonUtils.toJson(local)); for (final String server : peers.allServersWithoutMySelf()) { @@ -472,13 +472,13 @@ public Integer onCompleted(Response response) throws Exception { .error("NACOS-RAFT vote failed: {}, url: {}", response.getResponseBody(), url); return 1; } - + RaftPeer peer = JacksonUtils.toObj(response.getResponseBody(), RaftPeer.class); - + Loggers.RAFT.info("received approve from peer: {}", JacksonUtils.toJson(peer)); - + peers.decideLeader(peer); - + return 0; } }); @@ -488,7 +488,7 @@ public Integer onCompleted(Response response) throws Exception { } } } - + /** * Received vote. * @@ -499,55 +499,55 @@ public synchronized RaftPeer receivedVote(RaftPeer remote) { if (!peers.contains(remote)) { throw new IllegalStateException("can not find peer: " + remote.ip); } - + RaftPeer local = peers.get(NetUtils.localServer()); if (remote.term.get() <= local.term.get()) { String msg = "received illegitimate vote" + ", voter-term:" + remote.term + ", votee-term:" + local.term; - + Loggers.RAFT.info(msg); if (StringUtils.isEmpty(local.voteFor)) { local.voteFor = local.ip; } - + return local; } - + local.resetLeaderDue(); - + local.state = RaftPeer.State.FOLLOWER; local.voteFor = remote.ip; local.term.set(remote.term.get()); - + Loggers.RAFT.info("vote {} as leader, term: {}", remote.ip, remote.term); - + return local; } - + public class HeartBeat implements Runnable { - + @Override public void run() { try { - + if (!peers.isReady()) { return; } - + RaftPeer local = peers.local(); local.heartbeatDueMs -= GlobalExecutor.TICK_PERIOD_MS; if (local.heartbeatDueMs > 0) { return; } - + local.resetHeartbeatDue(); - + sendBeat(); } catch (Exception e) { Loggers.RAFT.warn("[RAFT] error while sending beat {}", e); } - + } - + private void sendBeat() throws IOException, InterruptedException { RaftPeer local = peers.local(); if (ApplicationUtils.getStandaloneMode() || local.state != RaftPeer.State.LEADER) { @@ -556,55 +556,55 @@ private void sendBeat() throws IOException, InterruptedException { if (Loggers.RAFT.isDebugEnabled()) { Loggers.RAFT.debug("[RAFT] send beat with {} keys.", datums.size()); } - + local.resetLeaderDue(); - + // build data ObjectNode packet = JacksonUtils.createEmptyJsonNode(); packet.replace("peer", JacksonUtils.transferToJsonNode(local)); - + ArrayNode array = JacksonUtils.createEmptyArrayNode(); - + if (switchDomain.isSendBeatOnly()) { Loggers.RAFT.info("[SEND-BEAT-ONLY] {}", String.valueOf(switchDomain.isSendBeatOnly())); } - + if (!switchDomain.isSendBeatOnly()) { for (Datum datum : datums.values()) { - + ObjectNode element = JacksonUtils.createEmptyJsonNode(); - + if (KeyBuilder.matchServiceMetaKey(datum.key)) { element.put("key", KeyBuilder.briefServiceMetaKey(datum.key)); } else if (KeyBuilder.matchInstanceListKey(datum.key)) { element.put("key", KeyBuilder.briefInstanceListkey(datum.key)); } element.put("timestamp", datum.timestamp.get()); - + array.add(element); } } - + packet.replace("datums", array); // broadcast Map params = new HashMap(1); params.put("beat", JacksonUtils.toJson(packet)); - + String content = JacksonUtils.toJson(params); - + ByteArrayOutputStream out = new ByteArrayOutputStream(); GZIPOutputStream gzip = new GZIPOutputStream(out); gzip.write(content.getBytes(StandardCharsets.UTF_8)); gzip.close(); - + byte[] compressedBytes = out.toByteArray(); String compressedContent = new String(compressedBytes, StandardCharsets.UTF_8); - + if (Loggers.RAFT.isDebugEnabled()) { Loggers.RAFT.debug("raw beat data size: {}, size of compressed data: {}", content.length(), compressedContent.length()); } - + for (final String server : peers.allServersWithoutMySelf()) { try { final String url = buildUrl(server, API_BEAT); @@ -620,14 +620,14 @@ public Integer onCompleted(Response response) throws Exception { MetricsMonitor.getLeaderSendBeatFailedException().increment(); return 1; } - + peers.update(JacksonUtils.toObj(response.getResponseBody(), RaftPeer.class)); if (Loggers.RAFT.isDebugEnabled()) { Loggers.RAFT.debug("receive beat response from: {}", url); } return 0; } - + @Override public void onThrowable(Throwable t) { Loggers.RAFT.error("NACOS-RAFT error while sending heart-beat to peer: {} {}", server, t); @@ -639,10 +639,10 @@ public void onThrowable(Throwable t) { MetricsMonitor.getLeaderSendBeatFailedException().increment(); } } - + } } - + /** * Received beat from leader. // TODO split method to multiple smaller method. * @@ -660,13 +660,13 @@ public RaftPeer receivedBeat(JsonNode beat) throws Exception { remote.heartbeatDueMs = peer.get("heartbeatDueMs").asLong(); remote.leaderDueMs = peer.get("leaderDueMs").asLong(); remote.voteFor = peer.get("voteFor").asText(); - + if (remote.state != RaftPeer.State.LEADER) { Loggers.RAFT.info("[RAFT] invalid state from master, state: {}, remote peer: {}", remote.state, JacksonUtils.toJson(remote)); throw new IllegalArgumentException("invalid state from master, state: " + remote.state); } - + if (local.term.get() > remote.term.get()) { Loggers.RAFT .info("[RAFT] out of date beat, beat-from-term: {}, beat-to-term: {}, remote peer: {}, and leaderDueMs: {}", @@ -674,32 +674,32 @@ public RaftPeer receivedBeat(JsonNode beat) throws Exception { throw new IllegalArgumentException( "out of date beat, beat-from-term: " + remote.term.get() + ", beat-to-term: " + local.term.get()); } - + if (local.state != RaftPeer.State.FOLLOWER) { - + Loggers.RAFT.info("[RAFT] make remote as leader, remote peer: {}", JacksonUtils.toJson(remote)); // mk follower local.state = RaftPeer.State.FOLLOWER; local.voteFor = remote.ip; } - + final JsonNode beatDatums = beat.get("datums"); local.resetLeaderDue(); local.resetHeartbeatDue(); - + peers.makeLeader(remote); - + if (!switchDomain.isSendBeatOnly()) { - + Map receivedKeysMap = new HashMap<>(datums.size()); - + for (Map.Entry entry : datums.entrySet()) { receivedKeysMap.put(entry.getKey(), 0); } - + // now check datums List batch = new ArrayList<>(); - + int processedCount = 0; if (Loggers.RAFT.isDebugEnabled()) { Loggers.RAFT @@ -708,11 +708,11 @@ public RaftPeer receivedBeat(JsonNode beat) throws Exception { } for (Object object : beatDatums) { processedCount = processedCount + 1; - + JsonNode entry = (JsonNode) object; String key = entry.get("key").asText(); final String datumKey; - + if (KeyBuilder.matchServiceMetaKey(key)) { datumKey = KeyBuilder.detailServiceMetaKey(key); } else if (KeyBuilder.matchInstanceListKey(key)) { @@ -721,35 +721,35 @@ public RaftPeer receivedBeat(JsonNode beat) throws Exception { // ignore corrupted key: continue; } - + long timestamp = entry.get("timestamp").asLong(); - + receivedKeysMap.put(datumKey, 1); - + try { if (datums.containsKey(datumKey) && datums.get(datumKey).timestamp.get() >= timestamp && processedCount < beatDatums.size()) { continue; } - + if (!(datums.containsKey(datumKey) && datums.get(datumKey).timestamp.get() >= timestamp)) { batch.add(datumKey); } - + if (batch.size() < 50 && processedCount < beatDatums.size()) { continue; } - + String keys = StringUtils.join(batch, ","); - + if (batch.size() <= 0) { continue; } - + Loggers.RAFT.info("get datums from leader: {}, batch size is {}, processedCount is {}" + ", datums' size is {}, RaftCore.datums' size is {}", getLeader().ip, batch.size(), processedCount, beatDatums.size(), datums.size()); - + // update datum entry String url = buildUrl(remote.ip, API_GET) + "?keys=" + URLEncoder.encode(keys, "UTF-8"); HttpClient.asyncHttpGet(url, null, null, new AsyncCompletionHandler() { @@ -758,18 +758,18 @@ public Integer onCompleted(Response response) throws Exception { if (response.getStatusCode() != HttpURLConnection.HTTP_OK) { return 1; } - + List datumList = JacksonUtils .toObj(response.getResponseBody(), new TypeReference>() { }); - + for (JsonNode datumJson : datumList) { Datum newDatum = null; OPERATE_LOCK.lock(); try { - + Datum oldDatum = getDatum(datumJson.get("key").asText()); - + if (oldDatum != null && datumJson.get("timestamp").asLong() <= oldDatum.timestamp .get()) { Loggers.RAFT @@ -778,7 +778,7 @@ public Integer onCompleted(Response response) throws Exception { datumJson.get("timestamp").asLong(), oldDatum.timestamp); continue; } - + if (KeyBuilder.matchServiceMetaKey(datumJson.get("key").asText())) { Datum serviceDatum = new Datum<>(); serviceDatum.key = datumJson.get("key").asText(); @@ -787,7 +787,7 @@ public Integer onCompleted(Response response) throws Exception { .toObj(datumJson.get("value").toString(), Service.class); newDatum = serviceDatum; } - + if (KeyBuilder.matchInstanceListKey(datumJson.get("key").asText())) { Datum instancesDatum = new Datum<>(); instancesDatum.key = datumJson.get("key").asText(); @@ -796,31 +796,31 @@ public Integer onCompleted(Response response) throws Exception { .toObj(datumJson.get("value").toString(), Instances.class); newDatum = instancesDatum; } - + if (newDatum == null || newDatum.value == null) { Loggers.RAFT.error("receive null datum: {}", datumJson); continue; } - + raftStore.write(newDatum); - + datums.put(newDatum.key, newDatum); notifier.addTask(newDatum.key, ApplyAction.CHANGE); - + local.resetLeaderDue(); - + if (local.term.get() + 100 > remote.term.get()) { getLeader().term.set(remote.term.get()); local.term.set(getLeader().term.get()); } else { local.term.addAndGet(100); } - + raftStore.updateTerm(local.term.get()); - + Loggers.RAFT.info("data updated, key: {}, timestamp: {}, from {}, local term: {}", newDatum.key, newDatum.timestamp, JacksonUtils.toJson(remote), local.term); - + } catch (Throwable e) { Loggers.RAFT .error("[RAFT-BEAT] failed to sync datum from leader, datum: {}", newDatum, @@ -833,22 +833,22 @@ public Integer onCompleted(Response response) throws Exception { return 0; } }); - + batch.clear(); - + } catch (Exception e) { Loggers.RAFT.error("[NACOS-RAFT] failed to handle beat entry, key: {}", datumKey); } - + } - + List deadKeys = new ArrayList<>(); for (Map.Entry entry : receivedKeysMap.entrySet()) { if (entry.getValue() == 0) { deadKeys.add(entry.getKey()); } } - + for (String deadKey : deadKeys) { try { deleteDatum(deadKey); @@ -856,12 +856,12 @@ public Integer onCompleted(Response response) throws Exception { Loggers.RAFT.error("[NACOS-RAFT] failed to remove entry, key={} {}", deadKey, e); } } - + } - + return local; } - + /** * Add listener for target key. * @@ -869,27 +869,27 @@ public Integer onCompleted(Response response) throws Exception { * @param listener new listener */ public void listen(String key, RecordListener listener) { - + List listenerList = listeners.get(key); if (listenerList != null && listenerList.contains(listener)) { return; } - + if (listenerList == null) { listenerList = new CopyOnWriteArrayList<>(); listeners.put(key, listenerList); } - + Loggers.RAFT.info("add listener: {}", key); - + listenerList.add(listener); - + // if data present, notify immediately for (Datum datum : datums.values()) { if (!listener.interests(datum.key)) { continue; } - + try { listener.onChange(datum.key, datum.value); } catch (Exception e) { @@ -897,19 +897,19 @@ public void listen(String key, RecordListener listener) { } } } - + /** * Remove listener for key. * * @param key key * @param listener listener */ - public void unlisten(String key, RecordListener listener) { - + public void unListen(String key, RecordListener listener) { + if (!listeners.containsKey(key)) { return; } - + for (RecordListener dl : listeners.get(key)) { // TODO maybe use equal: if (dl == listener) { @@ -918,23 +918,23 @@ public void unlisten(String key, RecordListener listener) { } } } - + public void unlistenAll(String key) { listeners.remove(key); } - + public void setTerm(long term) { peers.setTerm(term); } - + public boolean isLeader(String ip) { return peers.isLeader(ip); } - + public boolean isLeader() { return peers.isLeader(NetUtils.localServer()); } - + /** * Build api url. * @@ -948,36 +948,36 @@ public static String buildUrl(String ip, String api) { } return "http://" + ip + ApplicationUtils.getContextPath() + api; } - + public Datum getDatum(String key) { return datums.get(key); } - + public RaftPeer getLeader() { return peers.getLeader(); } - + public List getPeers() { return new ArrayList<>(peers.allPeers()); } - + public RaftPeerSet getPeerSet() { return peers; } - + public void setPeerSet(RaftPeerSet peerSet) { peers = peerSet; } - + public int datumSize() { return datums.size(); } - + public void addDatum(Datum datum) { datums.put(datum.key, datum); notifier.addTask(datum.key, ApplyAction.CHANGE); } - + /** * Load datum. * @@ -993,9 +993,9 @@ public void loadDatum(String key) { } catch (Exception e) { Loggers.RAFT.error("load datum failed: " + key, e); } - + } - + private void deleteDatum(String key) { Datum deleted; try { @@ -1009,21 +1009,21 @@ private void deleteDatum(String key) { Loggers.RAFT.warn("datum key decode failed: {}", key); } } - + public boolean isInitialized() { return initialized || !globalConfig.isDataWarmup(); } - + public int getNotifyTaskCount() { return notifier.getTaskSize(); } - + public class Notifier implements Runnable { - + private ConcurrentHashMap services = new ConcurrentHashMap<>(10 * 1024); - + private BlockingQueue tasks = new LinkedBlockingQueue<>(1024 * 1024); - + /** * Add notify task. * @@ -1031,55 +1031,55 @@ public class Notifier implements Runnable { * @param action action of datum */ public void addTask(String datumKey, ApplyAction action) { - + if (services.containsKey(datumKey) && action == ApplyAction.CHANGE) { return; } if (action == ApplyAction.CHANGE) { services.put(datumKey, StringUtils.EMPTY); } - + Loggers.RAFT.info("add task {}", datumKey); - + tasks.add(Pair.with(datumKey, action)); } - + public int getTaskSize() { return tasks.size(); } - + @Override public void run() { Loggers.RAFT.info("raft notifier started"); - + while (true) { try { - + Pair pair = tasks.take(); - + if (pair == null) { continue; } - + String datumKey = (String) pair.getValue0(); ApplyAction action = (ApplyAction) pair.getValue1(); - + services.remove(datumKey); - + Loggers.RAFT.info("remove task {}", datumKey); - + int count = 0; - + if (listeners.containsKey(KeyBuilder.SERVICE_META_KEY_PREFIX)) { - + if (KeyBuilder.matchServiceMetaKey(datumKey) && !KeyBuilder.matchSwitchKey(datumKey)) { - + for (RecordListener listener : listeners.get(KeyBuilder.SERVICE_META_KEY_PREFIX)) { try { if (action == ApplyAction.CHANGE) { listener.onChange(datumKey, getDatum(datumKey).value); } - + if (action == ApplyAction.DELETE) { listener.onDelete(datumKey); } @@ -1091,21 +1091,21 @@ public void run() { } } } - + if (!listeners.containsKey(datumKey)) { continue; } - + for (RecordListener listener : listeners.get(datumKey)) { - + count++; - + try { if (action == ApplyAction.CHANGE) { listener.onChange(datumKey, getDatum(datumKey).value); continue; } - + if (action == ApplyAction.DELETE) { listener.onDelete(datumKey); continue; @@ -1114,7 +1114,7 @@ public void run() { Loggers.RAFT.error("[NACOS-RAFT] error while notifying listener of key: {}", datumKey, e); } } - + if (Loggers.RAFT.isDebugEnabled()) { Loggers.RAFT.debug("[NACOS-RAFT] datum change notified, key: {}, listener count: {}", datumKey, count); diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java index 0d3aecfb7b0..e1159ee4ee0 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java @@ -71,21 +71,21 @@ @RestController @RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance") public class InstanceController { - + @Autowired private SwitchDomain switchDomain; - + @Autowired private PushService pushService; - + @Autowired private ServiceManager serviceManager; - + private DataSource pushDataSource = new DataSource() { - + @Override public String getData(PushService.PushClient client) { - + ObjectNode result = JacksonUtils.createEmptyJsonNode(); try { result = doSrvIpxt(client.getNamespaceId(), client.getServiceName(), client.getAgent(), @@ -94,14 +94,14 @@ public String getData(PushService.PushClient client) { } catch (Exception e) { Loggers.SRV_LOG.warn("PUSH-SERVICE: service is not modified", e); } - + // overdrive the cache millis to push mode result.put("cacheMillis", switchDomain.getPushCacheMillis(client.getServiceName())); - + return result.toString(); } }; - + /** * Register new instance. * @@ -113,17 +113,17 @@ public String getData(PushService.PushClient client) { @PostMapping @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE) public String register(HttpServletRequest request) throws Exception { - + final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); final String namespaceId = WebUtils .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); - + final Instance instance = parseInstance(request); - + serviceManager.registerInstance(namespaceId, serviceName, instance); return "ok"; } - + /** * Deregister instances. * @@ -138,17 +138,17 @@ public String deregister(HttpServletRequest request) throws Exception { Instance instance = getIpAddress(request); String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); - + Service service = serviceManager.getService(namespaceId, serviceName); if (service == null) { Loggers.SRV_LOG.warn("remove instance from non-exist service: {}", serviceName); return "ok"; } - + serviceManager.removeInstance(namespaceId, serviceName, instance.isEphemeral(), instance); return "ok"; } - + /** * Update instance. * @@ -164,11 +164,11 @@ public String update(HttpServletRequest request) throws Exception { final String namespaceId = WebUtils .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); final Instance instance = parseInstance(request); - + String agent = WebUtils.getUserAgent(request); - + ClientInfo clientInfo = new ClientInfo(agent); - + if (clientInfo.type == ClientInfo.ClientType.JAVA && clientInfo.version.compareTo(VersionUtil.parseVersion("1.0.0")) >= 0) { serviceManager.updateInstance(namespaceId, serviceName, instance); @@ -177,7 +177,7 @@ public String update(HttpServletRequest request) throws Exception { } return "ok"; } - + /** * Patch instance. * @@ -197,12 +197,12 @@ public String patch(HttpServletRequest request) throws Exception { if (StringUtils.isBlank(cluster)) { cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME); } - + Instance instance = serviceManager.getInstance(namespaceId, serviceName, cluster, ip, Integer.parseInt(port)); if (instance == null) { throw new IllegalArgumentException("instance not found"); } - + String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY); if (StringUtils.isNotBlank(metadata)) { instance.setMetadata(UtilsAndCommons.parseMetadata(metadata)); @@ -228,7 +228,7 @@ public String patch(HttpServletRequest request) throws Exception { serviceManager.updateInstance(namespaceId, serviceName, instance); return "ok"; } - + /** * Get all instance of input service. * @@ -239,9 +239,9 @@ public String patch(HttpServletRequest request) throws Exception { @GetMapping("/list") @Secured(parser = NamingResourceParser.class, action = ActionTypes.READ) public ObjectNode list(HttpServletRequest request) throws Exception { - + String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); - + String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); String agent = WebUtils.getUserAgent(request); String clusters = WebUtils.optional(request, "clusters", StringUtils.EMPTY); @@ -249,17 +249,17 @@ public ObjectNode list(HttpServletRequest request) throws Exception { int udpPort = Integer.parseInt(WebUtils.optional(request, "udpPort", "0")); String env = WebUtils.optional(request, "env", StringUtils.EMPTY); boolean isCheck = Boolean.parseBoolean(WebUtils.optional(request, "isCheck", "false")); - + String app = WebUtils.optional(request, "app", StringUtils.EMPTY); - + String tenant = WebUtils.optional(request, "tid", StringUtils.EMPTY); - + boolean healthyOnly = Boolean.parseBoolean(WebUtils.optional(request, "healthyOnly", "false")); - + return doSrvIpxt(namespaceId, serviceName, agent, clusters, clientIP, udpPort, env, isCheck, app, tenant, healthyOnly); } - + /** * Get detail information of specified instance. * @@ -270,27 +270,27 @@ public ObjectNode list(HttpServletRequest request) throws Exception { @GetMapping @Secured(parser = NamingResourceParser.class, action = ActionTypes.READ) public ObjectNode detail(HttpServletRequest request) throws Exception { - + String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, UtilsAndCommons.DEFAULT_CLUSTER_NAME); String ip = WebUtils.required(request, "ip"); int port = Integer.parseInt(WebUtils.required(request, "port")); - + Service service = serviceManager.getService(namespaceId, serviceName); if (service == null) { throw new NacosException(NacosException.NOT_FOUND, "no service " + serviceName + " found!"); } - + List clusters = new ArrayList<>(); clusters.add(cluster); - + List ips = service.allIPs(clusters); if (ips == null || ips.isEmpty()) { throw new NacosException(NacosException.NOT_FOUND, "no ips found for cluster " + cluster + " in service " + serviceName); } - + for (Instance instance : ips) { if (instance.getIp().equals(ip) && instance.getPort() == port) { ObjectNode result = JacksonUtils.createEmptyJsonNode(); @@ -305,10 +305,10 @@ public ObjectNode detail(HttpServletRequest request) throws Exception { return result; } } - + throw new NacosException(NacosException.NOT_FOUND, "no matched ip found!"); } - + /** * Create a beat for instance. * @@ -320,10 +320,10 @@ public ObjectNode detail(HttpServletRequest request) throws Exception { @PutMapping("/beat") @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE) public ObjectNode beat(HttpServletRequest request) throws Exception { - + ObjectNode result = JacksonUtils.createEmptyJsonNode(); result.put("clientBeatInterval", switchDomain.getClientBeatInterval()); - + String beat = WebUtils.optional(request, "beat", StringUtils.EMPTY); RsInfo clientBeat = null; if (StringUtils.isNotBlank(beat)) { @@ -347,16 +347,16 @@ public ObjectNode beat(HttpServletRequest request) throws Exception { String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); Loggers.SRV_LOG.debug("[CLIENT-BEAT] full arguments: beat: {}, serviceName: {}", clientBeat, serviceName); Instance instance = serviceManager.getInstance(namespaceId, serviceName, clusterName, ip, port); - + if (instance == null) { if (clientBeat == null) { result.put(CommonParams.CODE, NamingResponseCode.RESOURCE_NOT_FOUND); return result; } - + Loggers.SRV_LOG.warn("[CLIENT-BEAT] The instance has been removed for health mechanism, " + "perform data compensation operations, beat: {}, serviceName: {}", clientBeat, serviceName); - + instance = new Instance(); instance.setPort(clientBeat.getPort()); instance.setIp(clientBeat.getIp()); @@ -366,12 +366,12 @@ public ObjectNode beat(HttpServletRequest request) throws Exception { instance.setServiceName(serviceName); instance.setInstanceId(instance.getInstanceId()); instance.setEphemeral(clientBeat.isEphemeral()); - + serviceManager.registerInstance(namespaceId, serviceName, instance); } - + Service service = serviceManager.getService(namespaceId, serviceName); - + if (service == null) { throw new NacosException(NacosException.SERVER_ERROR, "service not found: " + serviceName + "@" + namespaceId); @@ -383,13 +383,13 @@ public ObjectNode beat(HttpServletRequest request) throws Exception { clientBeat.setCluster(clusterName); } service.processClientBeat(clientBeat); - + result.put(CommonParams.CODE, NamingResponseCode.OK); result.put("clientBeatInterval", instance.getInstanceHeartBeatInterval()); result.put(SwitchEntry.LIGHT_BEAT_ENABLED, switchDomain.isLightBeatEnabled()); return result; } - + /** * List all instance with health status. * @@ -399,10 +399,10 @@ public ObjectNode beat(HttpServletRequest request) throws Exception { */ @RequestMapping("/statuses") public ObjectNode listWithHealthStatus(@RequestParam String key) throws NacosException { - + String serviceName; String namespaceId; - + if (key.contains(UtilsAndCommons.NAMESPACE_SERVICE_CONNECTOR)) { namespaceId = key.split(UtilsAndCommons.NAMESPACE_SERVICE_CONNECTOR)[0]; serviceName = key.split(UtilsAndCommons.NAMESPACE_SERVICE_CONNECTOR)[1]; @@ -410,28 +410,28 @@ public ObjectNode listWithHealthStatus(@RequestParam String key) throws NacosExc namespaceId = Constants.DEFAULT_NAMESPACE_ID; serviceName = key; } - + Service service = serviceManager.getService(namespaceId, serviceName); - + if (service == null) { throw new NacosException(NacosException.NOT_FOUND, "service: " + serviceName + " not found."); } - + List ips = service.allIPs(); - + ObjectNode result = JacksonUtils.createEmptyJsonNode(); ArrayNode ipArray = JacksonUtils.createEmptyArrayNode(); - + for (Instance ip : ips) { ipArray.add(ip.toIpAddr() + "_" + ip.isHealthy()); } - + result.replace("ips", ipArray); return result; } - + private Instance parseInstance(HttpServletRequest request) throws Exception { - + String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); String app = WebUtils.optional(request, "app", "DEFAULT"); Instance instance = getIpAddress(request); @@ -445,12 +445,12 @@ private Instance parseInstance(HttpServletRequest request) throws Exception { if (StringUtils.isNotEmpty(metadata)) { instance.setMetadata(UtilsAndCommons.parseMetadata(metadata)); } - + instance.validate(); - + return instance; } - + private Instance getIpAddress(HttpServletRequest request) { final String ip = WebUtils.required(request, "ip"); final String port = WebUtils.required(request, "port"); @@ -458,20 +458,20 @@ private Instance getIpAddress(HttpServletRequest request) { if (StringUtils.isBlank(cluster)) { cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME); } - String enabledString = WebUtils.optional(request, "enabled", StringUtils.EMPTY); + String enabledStr = WebUtils.optional(request, "enabled", StringUtils.EMPTY); boolean enabled; - if (StringUtils.isBlank(enabledString)) { + if (StringUtils.isBlank(enabledStr)) { enabled = BooleanUtils.toBoolean(WebUtils.optional(request, "enable", "true")); } else { - enabled = BooleanUtils.toBoolean(enabledString); + enabled = BooleanUtils.toBoolean(enabledStr); } - + boolean ephemeral = BooleanUtils.toBoolean( WebUtils.optional(request, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral()))); - + String weight = WebUtils.optional(request, "weight", "1"); boolean healthy = BooleanUtils.toBoolean(WebUtils.optional(request, "healthy", "true")); - + Instance instance = new Instance(); instance.setPort(Integer.parseInt(port)); instance.setIp(ip); @@ -480,16 +480,16 @@ private Instance getIpAddress(HttpServletRequest request) { instance.setHealthy(healthy); instance.setEnabled(enabled); instance.setEphemeral(ephemeral); - + return instance; } - + private void checkIfDisabled(Service service) throws Exception { if (!service.getEnabled()) { throw new Exception("service is disabled now."); } } - + /** * Get service full information with instances. * @@ -509,11 +509,11 @@ private void checkIfDisabled(Service service) throws Exception { */ public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent, String clusters, String clientIP, int udpPort, String env, boolean isCheck, String app, String tid, boolean healthyOnly) throws Exception { - + ClientInfo clientInfo = new ClientInfo(agent); ObjectNode result = JacksonUtils.createEmptyJsonNode(); Service service = serviceManager.getService(namespaceId, serviceName); - + if (service == null) { if (Loggers.SRV_LOG.isDebugEnabled()) { Loggers.SRV_LOG.debug("no instance to serve for service: {}", serviceName); @@ -523,15 +523,15 @@ public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent result.replace("hosts", JacksonUtils.createEmptyArrayNode()); return result; } - + checkIfDisabled(service); - + long cacheMillis = switchDomain.getDefaultCacheMillis(); - + // now try to enable the push try { if (udpPort > 0 && pushService.canEnablePush(agent)) { - + pushService .addClient(namespaceId, serviceName, clusters, agent, new InetSocketAddress(clientIP, udpPort), pushDataSource, tid, app); @@ -542,29 +542,29 @@ public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent .error("[NACOS-API] failed to added push client {}, {}:{}", clientInfo, clientIP, udpPort, e); cacheMillis = switchDomain.getDefaultCacheMillis(); } - + List srvedIPs; - + srvedIPs = service.srvIPs(Arrays.asList(StringUtils.split(clusters, ","))); - + // filter ips using selector: if (service.getSelector() != null && StringUtils.isNotBlank(clientIP)) { srvedIPs = service.getSelector().select(clientIP, srvedIPs); } - + if (CollectionUtils.isEmpty(srvedIPs)) { - + if (Loggers.SRV_LOG.isDebugEnabled()) { Loggers.SRV_LOG.debug("no instance to serve for service: {}", serviceName); } - + if (clientInfo.type == ClientInfo.ClientType.JAVA && clientInfo.version.compareTo(VersionUtil.parseVersion("1.0.0")) >= 0) { result.put("dom", serviceName); } else { result.put("dom", NamingUtils.getServiceName(serviceName)); } - + result.put("hosts", JacksonUtils.createEmptyArrayNode()); result.put("name", serviceName); result.put("cacheMillis", cacheMillis); @@ -576,57 +576,57 @@ public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent result.put("metadata", JacksonUtils.transferToJsonNode(service.getMetadata())); return result; } - + Map> ipMap = new HashMap<>(2); ipMap.put(Boolean.TRUE, new ArrayList<>()); ipMap.put(Boolean.FALSE, new ArrayList<>()); - + for (Instance ip : srvedIPs) { ipMap.get(ip.isHealthy()).add(ip); } - + if (isCheck) { result.put("reachProtectThreshold", false); } - + double threshold = service.getProtectThreshold(); - + if ((float) ipMap.get(Boolean.TRUE).size() / srvedIPs.size() <= threshold) { - + Loggers.SRV_LOG.warn("protect threshold reached, return all ips, service: {}", serviceName); if (isCheck) { result.put("reachProtectThreshold", true); } - + ipMap.get(Boolean.TRUE).addAll(ipMap.get(Boolean.FALSE)); ipMap.get(Boolean.FALSE).clear(); } - + if (isCheck) { result.put("protectThreshold", service.getProtectThreshold()); result.put("reachLocalSiteCallThreshold", false); - + return JacksonUtils.createEmptyJsonNode(); } - + ArrayNode hosts = JacksonUtils.createEmptyArrayNode(); - + for (Map.Entry> entry : ipMap.entrySet()) { List ips = entry.getValue(); - + if (healthyOnly && !entry.getKey()) { continue; } - + for (Instance instance : ips) { - + // remove disabled instance: if (!instance.isEnabled()) { continue; } - + ObjectNode ipObj = JacksonUtils.createEmptyJsonNode(); - + ipObj.put("ip", instance.getIp()); ipObj.put("port", instance.getPort()); // deprecated since nacos 1.0.0: @@ -644,13 +644,13 @@ public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent } else { ipObj.put("serviceName", NamingUtils.getServiceName(instance.getServiceName())); } - + ipObj.put("ephemeral", instance.isEphemeral()); hosts.add(ipObj); - + } } - + result.replace("hosts", hosts); if (clientInfo.type == ClientInfo.ClientType.JAVA && clientInfo.version.compareTo(VersionUtil.parseVersion("1.0.0")) >= 0) { diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java b/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java index 3380a34ebf3..10c94ac6f80 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java @@ -43,38 +43,38 @@ * @author jifengnan 2019-04-26 */ public class Cluster extends com.alibaba.nacos.api.naming.pojo.Cluster implements Cloneable { - + private static final String CLUSTER_NAME_SYNTAX = "[0-9a-zA-Z-]+"; - + /** * a addition for same site routing, can group multiple sites into a region, like Hangzhou, Shanghai, etc. */ private String sitegroup = StringUtils.EMPTY; - + private int defCkport = 80; - + private int defIpPort = -1; - + @JsonIgnore private HealthCheckTask checkTask; - + @JsonIgnore private Set persistentInstances = new HashSet<>(); - + @JsonIgnore private Set ephemeralInstances = new HashSet<>(); - + @JsonIgnore private Service service; - + @JsonIgnore private volatile boolean inited = false; - + private Map metadata = new ConcurrentHashMap<>(); - + public Cluster() { } - + /** * Create a cluster. * @@ -92,7 +92,7 @@ public Cluster(String clusterName, Service service) { this.service = service; validate(); } - + /** * Reason why method is not camel is that the old version has released, and the method name will be as the key * serialize and deserialize for Json. So ignore checkstyle. @@ -104,7 +104,7 @@ public int getDefIPPort() { // for compatibility with old entries return defIpPort == -1 ? defCkport : defIpPort; } - + @SuppressWarnings("checkstyle:abbreviationaswordinname") public void setDefIPPort(int defIpPort) { if (defIpPort == 0) { @@ -112,7 +112,7 @@ public void setDefIPPort(int defIpPort) { } this.defIpPort = defIpPort; } - + /** * Get all instances. * @@ -124,7 +124,7 @@ public List allIPs() { allInstances.addAll(ephemeralInstances); return allInstances; } - + /** * Get all ephemeral or consistence instances. * @@ -134,7 +134,7 @@ public List allIPs() { public List allIPs(boolean ephemeral) { return ephemeral ? new ArrayList<>(ephemeralInstances) : new ArrayList<>(persistentInstances); } - + /** * Init cluster. */ @@ -143,11 +143,11 @@ public void init() { return; } checkTask = new HealthCheckTask(this); - + HealthCheckReactor.scheduleCheck(checkTask); inited = true; } - + /** * Destroy cluster. */ @@ -156,16 +156,16 @@ public void destroy() { checkTask.setCancelled(true); } } - + @JsonIgnore public HealthCheckTask getHealthCheckTask() { return checkTask; } - + public Service getService() { return service; } - + /** * Replace the service for the current cluster. * @@ -181,7 +181,7 @@ public void setService(Service service) { } this.service = service; } - + /** * this method has been deprecated, the service name shouldn't be changed. * @@ -194,7 +194,7 @@ public void setService(Service service) { public void setServiceName(String serviceName) { super.setServiceName(serviceName); } - + /** * Get the service name of the current cluster. * @@ -211,7 +211,7 @@ public String getServiceName() { return super.getServiceName(); } } - + @Override public Cluster clone() throws CloneNotSupportedException { super.clone(); @@ -222,11 +222,11 @@ public Cluster clone() throws CloneNotSupportedException { cluster.metadata = new HashMap<>(metadata); return cluster; } - + public boolean isEmpty() { return ephemeralInstances.isEmpty() && persistentInstances.isEmpty(); } - + /** * Update instance list. * @@ -234,33 +234,33 @@ public boolean isEmpty() { * @param ephemeral whether these instances are ephemeral */ public void updateIps(List ips, boolean ephemeral) { - + Set toUpdateInstances = ephemeral ? ephemeralInstances : persistentInstances; - + HashMap oldIpMap = new HashMap<>(toUpdateInstances.size()); - + for (Instance ip : toUpdateInstances) { oldIpMap.put(ip.getDatumKey(), ip); } - + List 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(), @@ -268,86 +268,86 @@ public void updateIps(List ips, boolean ephemeral) { } } } - + List 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 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); - + if (ephemeral) { ephemeralInstances = toUpdateInstances; } else { persistentInstances = toUpdateInstances; } } - + private List updatedIps(Collection newInstance, Collection oldInstance) { - + List intersects = (List) CollectionUtils.intersection(newInstance, oldInstance); - Map stringIpAddressMap = new ConcurrentHashMap<>(intersects.size()); - + Map ipAddressMap = new ConcurrentHashMap<>(intersects.size()); + for (Instance instance : intersects) { - stringIpAddressMap.put(instance.getIp() + ":" + instance.getPort(), instance); + ipAddressMap.put(instance.getIp() + ":" + instance.getPort(), instance); } - + Map intersectMap = new ConcurrentHashMap<>(newInstance.size() + oldInstance.size()); Map instanceMap = new ConcurrentHashMap<>(newInstance.size()); - Map instanceMap1 = new ConcurrentHashMap<>(newInstance.size()); - + Map instancesMap = new ConcurrentHashMap<>(newInstance.size()); + for (Instance instance : oldInstance) { - if (stringIpAddressMap.containsKey(instance.getIp() + ":" + instance.getPort())) { + if (ipAddressMap.containsKey(instance.getIp() + ":" + instance.getPort())) { intersectMap.put(instance.toString(), 1); } } - + for (Instance instance : newInstance) { - if (stringIpAddressMap.containsKey(instance.getIp() + ":" + instance.getPort())) { - + if (ipAddressMap.containsKey(instance.getIp() + ":" + instance.getPort())) { + if (intersectMap.containsKey(instance.toString())) { intersectMap.put(instance.toString(), 2); } else { intersectMap.put(instance.toString(), 1); } } - - instanceMap1.put(instance.toString(), instance); - + + instancesMap.put(instance.toString(), instance); + } - + for (Map.Entry entry : intersectMap.entrySet()) { String key = entry.getKey(); Integer value = entry.getValue(); - + if (value == 1) { - if (instanceMap1.containsKey(key)) { - instanceMap.put(key, instanceMap1.get(key)); + if (instancesMap.containsKey(key)) { + instanceMap.put(key, instancesMap.get(key)); } } } - + return new ArrayList<>(instanceMap.values()); } - + private List subtract(Collection oldIp, Collection ips) { Map ipsMap = new HashMap<>(ips.size()); for (Instance instance : ips) { @@ -363,84 +363,84 @@ private List subtract(Collection oldIp, Collection } return instanceResult; } - + @Override public int hashCode() { return Objects.hash(getName()); } - + @Override public boolean equals(Object obj) { if (!(obj instanceof Cluster)) { return false; } - + return getName().equals(((Cluster) obj).getName()); } - + public int getDefCkport() { return defCkport; } - + public void setDefCkport(int defCkport) { this.defCkport = defCkport; } - + /** * Update cluster from other cluster. * * @param cluster new cluster */ public void update(Cluster cluster) { - + if (!getHealthChecker().equals(cluster.getHealthChecker())) { Loggers.SRV_LOG.info("[CLUSTER-UPDATE] {}:{}:, healthChecker: {} -> {}", getService().getName(), getName(), getHealthChecker().toString(), cluster.getHealthChecker().toString()); setHealthChecker(cluster.getHealthChecker()); } - + if (defCkport != cluster.getDefCkport()) { Loggers.SRV_LOG .info("[CLUSTER-UPDATE] {}:{}, defCkport: {} -> {}", getService().getName(), getName(), defCkport, cluster.getDefCkport()); defCkport = cluster.getDefCkport(); } - + if (defIpPort != cluster.getDefIPPort()) { Loggers.SRV_LOG .info("[CLUSTER-UPDATE] {}:{}, defIPPort: {} -> {}", getService().getName(), getName(), defIpPort, cluster.getDefIPPort()); defIpPort = cluster.getDefIPPort(); } - + if (!StringUtils.equals(sitegroup, cluster.getSitegroup())) { Loggers.SRV_LOG .info("[CLUSTER-UPDATE] {}:{}, sitegroup: {} -> {}", getService().getName(), getName(), sitegroup, cluster.getSitegroup()); sitegroup = cluster.getSitegroup(); } - + if (isUseIPPort4Check() != cluster.isUseIPPort4Check()) { Loggers.SRV_LOG.info("[CLUSTER-UPDATE] {}:{}, useIPPort4Check: {} -> {}", getService().getName(), getName(), isUseIPPort4Check(), cluster.isUseIPPort4Check()); setUseIPPort4Check(cluster.isUseIPPort4Check()); } - + metadata = cluster.getMetadata(); } - + public String getSitegroup() { return sitegroup; } - + public void setSitegroup(String sitegroup) { this.sitegroup = sitegroup; } - + public boolean contains(Instance ip) { return persistentInstances.contains(ip) || ephemeralInstances.contains(ip); } - + /** * validate the current cluster. * diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java index 4b2dea6f1ca..3c15f57b935 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java @@ -72,44 +72,44 @@ */ @Component public class ServiceManager implements RecordListener { - + /** * Map(namespace, Map(group::serviceName, Service)). */ private final Map> serviceMap = new ConcurrentHashMap<>(); - + private final LinkedBlockingDeque toBeUpdatedServicesQueue = new LinkedBlockingDeque<>(1024 * 1024); - + private final Synchronizer synchronizer = new ServiceStatusSynchronizer(); - + private final Lock lock = new ReentrantLock(); - + @Resource(name = "consistencyDelegate") private ConsistencyService consistencyService; - + private final SwitchDomain switchDomain; - + private final DistroMapper distroMapper; - + private final ServerMemberManager memberManager; - + private final PushService pushService; - + private final RaftPeerSet raftPeerSet; - + private int maxFinalizeCount = 3; - + private final Object putServiceLock = new Object(); - + @Value("${nacos.naming.empty-service.auto-clean:false}") private boolean emptyServiceAutoClean; - + @Value("${nacos.naming.empty-service.clean.initial-delay-ms:60000}") private int cleanEmptyServiceDelay; - + @Value("${nacos.naming.empty-service.clean.period-time-ms:20000}") private int cleanEmptyServicePeriod; - + public ServiceManager(SwitchDomain switchDomain, DistroMapper distroMapper, ServerMemberManager memberManager, PushService pushService, RaftPeerSet raftPeerSet) { this.switchDomain = switchDomain; @@ -118,32 +118,32 @@ public ServiceManager(SwitchDomain switchDomain, DistroMapper distroMapper, Serv this.pushService = pushService; this.raftPeerSet = raftPeerSet; } - + /** * Init service maneger. */ @PostConstruct public void init() { - + UtilsAndCommons.SERVICE_SYNCHRONIZATION_EXECUTOR.schedule(new ServiceReporter(), 60000, TimeUnit.MILLISECONDS); - + UtilsAndCommons.SERVICE_UPDATE_EXECUTOR.submit(new UpdatedServiceProcessor()); - + if (emptyServiceAutoClean) { - + Loggers.SRV_LOG.info("open empty service auto clean job, initialDelay : {} ms, period : {} ms", cleanEmptyServiceDelay, cleanEmptyServicePeriod); - + // delay 60s, period 20s; - + // This task is not recommended to be performed frequently in order to avoid // the possibility that the service cache information may just be deleted // and then created due to the heartbeat mechanism - + GlobalExecutor.scheduleServiceAutoClean(new EmptyServiceAutoClean(), cleanEmptyServiceDelay, cleanEmptyServicePeriod); } - + try { Loggers.SRV_LOG.info("listen for service meta change"); consistencyService.listen(KeyBuilder.SERVICE_META_KEY_PREFIX, this); @@ -151,11 +151,11 @@ public void init() { Loggers.SRV_LOG.error("listen for service meta change failed!"); } } - + public Map chooseServiceMap(String namespaceId) { return serviceMap.get(namespaceId); } - + /** * Add a service into queue to update. * @@ -177,17 +177,17 @@ public void addUpdatedServiceToQueue(String namespaceId, String serviceName, Str lock.unlock(); } } - + @Override public boolean interests(String key) { return KeyBuilder.matchServiceMetaKey(key) && !KeyBuilder.matchSwitchKey(key); } - + @Override public boolean matchUnlistenKey(String key) { return KeyBuilder.matchServiceMetaKey(key) && !KeyBuilder.matchSwitchKey(key); } - + @Override public void onChange(String key, Service service) throws Exception { try { @@ -195,15 +195,15 @@ public void onChange(String key, Service service) throws Exception { Loggers.SRV_LOG.warn("received empty push from raft, key: {}", key); return; } - + if (StringUtils.isBlank(service.getNamespaceId())) { service.setNamespaceId(Constants.DEFAULT_NAMESPACE_ID); } - + Loggers.RAFT.info("[RAFT-NOTIFIER] datum is changed, key: {}, value: {}", key, service); - + Service oldDom = getService(service.getNamespaceId(), service.getName()); - + if (oldDom != null) { oldDom.update(service); // re-listen to handle the situation when the underlying listener is removed: @@ -220,34 +220,34 @@ public void onChange(String key, Service service) throws Exception { Loggers.SRV_LOG.error("[NACOS-SERVICE] error while processing service update", e); } } - + @Override public void onDelete(String key) throws Exception { String namespace = KeyBuilder.getNamespace(key); String name = KeyBuilder.getServiceName(key); Service service = chooseServiceMap(namespace).get(name); Loggers.RAFT.info("[RAFT-NOTIFIER] datum is deleted, key: {}", key); - + if (service != null) { service.destroy(); consistencyService.remove(KeyBuilder.buildInstanceListKey(namespace, name, true)); - + consistencyService.remove(KeyBuilder.buildInstanceListKey(namespace, name, false)); - - consistencyService.unlisten(KeyBuilder.buildServiceMetaKey(namespace, name), service); + + consistencyService.unListen(KeyBuilder.buildServiceMetaKey(namespace, name), service); Loggers.SRV_LOG.info("[DEAD-SERVICE] {}", service.toJson()); } - + chooseServiceMap(namespace).remove(name); } - + private class UpdatedServiceProcessor implements Runnable { - + //get changed service from other server asynchronously @Override public void run() { ServiceKey serviceKey = null; - + try { while (true) { try { @@ -255,7 +255,7 @@ public void run() { } catch (Exception e) { Loggers.EVT_LOG.error("[UPDATE-DOMAIN] Exception while taking item from LinkedBlockingDeque."); } - + if (serviceKey == null) { continue; } @@ -266,21 +266,21 @@ public void run() { } } } - + private class ServiceUpdater implements Runnable { - + String namespaceId; - + String serviceName; - + String serverIP; - + public ServiceUpdater(ServiceKey serviceKey) { this.namespaceId = serviceKey.getNamespaceId(); this.serviceName = serviceKey.getServiceName(); this.serverIP = serviceKey.getServerIP(); } - + @Override public void run() { try { @@ -292,11 +292,11 @@ public void run() { } } } - + public RaftPeer getMySelfClusterState() { return raftPeerSet.local(); } - + /** * Update health status of instance in service. * @@ -307,27 +307,27 @@ public RaftPeer getMySelfClusterState() { public void updatedHealthStatus(String namespaceId, String serviceName, String serverIP) { Message msg = synchronizer.get(serverIP, UtilsAndCommons.assembleFullServiceName(namespaceId, serviceName)); JsonNode serviceJson = JacksonUtils.toObj(msg.getData()); - + ArrayNode ipList = (ArrayNode) serviceJson.get("ips"); Map ipsMap = new HashMap<>(ipList.size()); for (int i = 0; i < ipList.size(); i++) { - + String ip = ipList.get(i).asText(); String[] strings = ip.split("_"); ipsMap.put(strings[0], strings[1]); } - + Service service = getService(namespaceId, serviceName); - + if (service == null) { return; } - + boolean changed = false; - + List instances = service.allIPs(); for (Instance instance : instances) { - + boolean valid = Boolean.parseBoolean(ipsMap.get(instance.toIpAddr())); if (valid != instance.isHealthy()) { changed = true; @@ -337,7 +337,7 @@ public void updatedHealthStatus(String namespaceId, String serviceName, String s instance.getClusterName()); } } - + if (changed) { pushService.serviceChanged(service); if (Loggers.EVT_LOG.isDebugEnabled()) { @@ -351,33 +351,33 @@ public void updatedHealthStatus(String namespaceId, String serviceName, String s service.getName(), stringBuilder.toString()); } } - + } - + public Set getAllServiceNames(String namespaceId) { return serviceMap.get(namespaceId).keySet(); } - + public Map> getAllServiceNames() { - + Map> namesMap = new HashMap<>(16); for (String namespaceId : serviceMap.keySet()) { namesMap.put(namespaceId, serviceMap.get(namespaceId).keySet()); } return namesMap; } - + public Set getAllNamespaces() { return serviceMap.keySet(); } - + public List getAllServiceNameList(String namespaceId) { if (chooseServiceMap(namespaceId) == null) { return new ArrayList<>(); } return new ArrayList<>(chooseServiceMap(namespaceId).keySet()); } - + public Map> getResponsibleServices() { Map> result = new HashMap<>(16); for (String namespaceId : serviceMap.keySet()) { @@ -391,7 +391,7 @@ public Map> getResponsibleServices() { } return result; } - + public int getResponsibleServiceCount() { int serviceCount = 0; for (String namespaceId : serviceMap.keySet()) { @@ -403,7 +403,7 @@ public int getResponsibleServiceCount() { } return serviceCount; } - + public int getResponsibleInstanceCount() { Map> responsibleServices = getResponsibleServices(); int count = 0; @@ -412,10 +412,10 @@ public int getResponsibleInstanceCount() { count += service.allIPs().size(); } } - + return count; } - + /** * Fast remove service. * @@ -426,23 +426,23 @@ public int getResponsibleInstanceCount() { * @throws Exception exception */ public void easyRemoveService(String namespaceId, String serviceName) throws Exception { - + Service service = getService(namespaceId, serviceName); if (service == null) { throw new IllegalArgumentException("specified service not exist, serviceName : " + serviceName); } - + consistencyService.remove(KeyBuilder.buildServiceMetaKey(namespaceId, serviceName)); } - + public void addOrReplaceService(Service service) throws NacosException { consistencyService.put(KeyBuilder.buildServiceMetaKey(service.getNamespaceId(), service.getName()), service); } - + public void createEmptyService(String namespaceId, String serviceName, boolean local) throws NacosException { createServiceIfAbsent(namespaceId, serviceName, local, null); } - + /** * Create service if not exist. * @@ -456,7 +456,7 @@ public void createServiceIfAbsent(String namespaceId, String serviceName, boolea 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); @@ -470,14 +470,14 @@ public void createServiceIfAbsent(String namespaceId, String serviceName, boolea service.getClusterMap().put(cluster.getName(), cluster); } service.validate(); - + putServiceAndInit(service); if (!local) { addOrReplaceService(service); } } } - + /** * Register an instance to a service in AP mode. * @@ -489,19 +489,19 @@ public void createServiceIfAbsent(String namespaceId, String serviceName, boolea * @throws Exception any error occurred in the process */ public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException { - + createEmptyService(namespaceId, serviceName, instance.isEphemeral()); - + Service service = getService(namespaceId, serviceName); - + if (service == null) { throw new NacosException(NacosException.INVALID_PARAM, "service not found, namespace: " + namespaceId + ", service: " + serviceName); } - + addInstance(namespaceId, serviceName, instance.isEphemeral(), instance); } - + /** * Update instance to service. * @@ -511,21 +511,21 @@ public void registerInstance(String namespaceId, String serviceName, Instance in * @throws NacosException nacos exception */ public void updateInstance(String namespaceId, String serviceName, Instance instance) throws NacosException { - + Service service = getService(namespaceId, serviceName); - + if (service == null) { throw new NacosException(NacosException.INVALID_PARAM, "service not found, namespace: " + namespaceId + ", service: " + serviceName); } - + if (!service.allIPs().contains(instance)) { throw new NacosException(NacosException.INVALID_PARAM, "instance not exist: " + instance); } - + addInstance(namespaceId, serviceName, instance.isEphemeral(), instance); } - + /** * Add instance to service. * @@ -537,21 +537,21 @@ public void updateInstance(String namespaceId, String serviceName, Instance inst */ public void addInstance(String namespaceId, String serviceName, boolean ephemeral, Instance... ips) throws NacosException { - + String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral); - + Service service = getService(namespaceId, serviceName); - + synchronized (service) { List instanceList = addIpAddresses(service, ephemeral, ips); - + Instances instances = new Instances(); instances.setInstanceList(instanceList); - + consistencyService.put(key, instances); } } - + /** * Remove instance from service. * @@ -564,48 +564,48 @@ public void addInstance(String namespaceId, String serviceName, boolean ephemera public void removeInstance(String namespaceId, String serviceName, boolean ephemeral, Instance... ips) throws NacosException { Service service = getService(namespaceId, serviceName); - + synchronized (service) { removeInstance(namespaceId, serviceName, ephemeral, service, ips); } } - + private void removeInstance(String namespaceId, String serviceName, boolean ephemeral, Service service, Instance... ips) throws NacosException { - + String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral); - + List instanceList = substractIpAddresses(service, ephemeral, ips); - + Instances instances = new Instances(); instances.setInstanceList(instanceList); - + consistencyService.put(key, instances); } - + public Instance getInstance(String namespaceId, String serviceName, String cluster, String ip, int port) { Service service = getService(namespaceId, serviceName); if (service == null) { return null; } - + List clusters = new ArrayList<>(); clusters.add(cluster); - + List ips = service.allIPs(clusters); if (ips == null || ips.isEmpty()) { return null; } - + for (Instance instance : ips) { if (instance.getIp().equals(ip) && instance.getPort() == port) { return instance; } } - + return null; } - + /** * Compare and get new instance list. * @@ -618,26 +618,26 @@ public Instance getInstance(String namespaceId, String serviceName, String clust */ public List updateIpAddresses(Service service, String action, boolean ephemeral, Instance... ips) throws NacosException { - + Datum datum = consistencyService .get(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), ephemeral)); - + List currentIPs = service.allIPs(ephemeral); Map currentInstances = new HashMap<>(currentIPs.size()); Set currentInstanceIds = Sets.newHashSet(); - + for (Instance instance : currentIPs) { currentInstances.put(instance.toIpAddr(), instance); currentInstanceIds.add(instance.getInstanceId()); } - + Map instanceMap; if (datum != null) { 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); @@ -647,36 +647,36 @@ public List updateIpAddresses(Service service, String action, boolean .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.remove(instance.getDatumKey()); } 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()); } - + private List substractIpAddresses(Service service, boolean ephemeral, Instance... ips) throws NacosException { return updateIpAddresses(service, UtilsAndCommons.UPDATE_INSTANCE_ACTION_REMOVE, ephemeral, ips); } - + private List addIpAddresses(Service service, boolean ephemeral, Instance... ips) throws NacosException { return updateIpAddresses(service, UtilsAndCommons.UPDATE_INSTANCE_ACTION_ADD, ephemeral, ips); } - + private Map setValid(List oldInstances, Map map) { - + Map instanceMap = new HashMap<>(oldInstances.size()); for (Instance instance : oldInstances) { Instance instance1 = map.get(instance.toIpAddr()); @@ -688,18 +688,18 @@ private Map setValid(List oldInstances, Map searchServices(String namespaceId, String regex) { result.add(service); } } - + return result; } - + public int getServiceCount() { int serviceCount = 0; for (String namespaceId : serviceMap.keySet()) { @@ -753,7 +753,7 @@ public int getServiceCount() { } return serviceCount; } - + public int getInstanceCount() { int total = 0; for (String namespaceId : serviceMap.keySet()) { @@ -763,20 +763,20 @@ public int getInstanceCount() { } return total; } - + public Map getServiceMap(String namespaceId) { return serviceMap.get(namespaceId); } - + public int getPagedService(String namespaceId, int startPage, int pageSize, String param, String containedInstance, List serviceList, boolean hasIpCount) { - + List matchList; - + if (chooseServiceMap(namespaceId) == null) { return 0; } - + if (StringUtils.isNotBlank(param)) { StringJoiner regex = new StringJoiner(Constants.SERVICE_INFO_SPLITER); for (String s : param.split(Constants.SERVICE_INFO_SPLITER)) { @@ -787,14 +787,14 @@ public int getPagedService(String namespaceId, int startPage, int pageSize, Stri } else { matchList = new ArrayList<>(chooseServiceMap(namespaceId).values()); } - + if (!CollectionUtils.isEmpty(matchList) && hasIpCount) { matchList = matchList.stream().filter(s -> !CollectionUtils.isEmpty(s.allIPs())) .collect(Collectors.toList()); } - + if (StringUtils.isNotBlank(containedInstance)) { - + boolean contained; for (int i = 0; i < matchList.size(); i++) { Service service = matchList.get(i); @@ -819,41 +819,41 @@ public int getPagedService(String namespaceId, int startPage, int pageSize, Stri } } } - + if (pageSize >= matchList.size()) { serviceList.addAll(matchList); return matchList.size(); } - + for (int i = 0; i < matchList.size(); i++) { if (i < startPage * pageSize) { continue; } - + serviceList.add(matchList.get(i)); - + if (serviceList.size() >= pageSize) { break; } } - + return matchList.size(); } - + public static class ServiceChecksum { - + public String namespaceId; - + public Map serviceName2Checksum = new HashMap(); - + public ServiceChecksum() { this.namespaceId = Constants.DEFAULT_NAMESPACE_ID; } - + public ServiceChecksum(String namespaceId) { this.namespaceId = namespaceId; } - + /** * Add service checksum. * @@ -869,16 +869,16 @@ public void addItem(String serviceName, String checksum) { serviceName2Checksum.put(serviceName, checksum); } } - + private class EmptyServiceAutoClean implements Runnable { - + @Override public void run() { - + // Parallel flow opening threshold - + int parallelSize = 100; - + serviceMap.forEach((namespace, stringServiceMap) -> { Stream> stream = null; if (stringServiceMap.size() > parallelSize) { @@ -891,11 +891,11 @@ public void run() { return distroMapper.responsible(serviceName); }).forEach(entry -> stringServiceMap.computeIfPresent(entry.getKey(), (serviceName, service) -> { if (service.isEmpty()) { - + // To avoid violent Service removal, the number of times the Service // experiences Empty is determined by finalizeCnt, and if the specified // value is reached, it is removed - + if (service.getFinalizeCount() > maxFinalizeCount) { Loggers.SRV_LOG.warn("namespace : {}, [{}] services are automatically cleaned", namespace, serviceName); @@ -906,9 +906,9 @@ public void run() { + "error : {}", namespace, serviceName, e); } } - + service.setFinalizeCount(service.getFinalizeCount() + 1); - + Loggers.SRV_LOG .debug("namespace : {}, [{}] The number of times the current service experiences " + "an empty instance is : {}", namespace, serviceName, @@ -921,50 +921,50 @@ public void run() { }); } } - + private class ServiceReporter implements Runnable { - + @Override public void run() { try { - + Map> allServiceNames = getAllServiceNames(); - + if (allServiceNames.size() <= 0) { //ignore return; } - + for (String namespaceId : allServiceNames.keySet()) { - + ServiceChecksum checksum = new ServiceChecksum(namespaceId); - + for (String serviceName : allServiceNames.get(namespaceId)) { if (!distroMapper.responsible(serviceName)) { continue; } - + Service service = getService(namespaceId, serviceName); - + if (service == null || service.isEmpty()) { continue; } - + service.recalculateChecksum(); - + checksum.addItem(serviceName, service.getChecksum()); } - + Message msg = new Message(); - + msg.setData(JacksonUtils.toJson(checksum)); - + Collection sameSiteServers = memberManager.allMembers(); - + if (sameSiteServers == null || sameSiteServers.size() <= 0) { return; } - + for (Member server : sameSiteServers) { if (server.getAddress().equals(NetUtils.localServer())) { continue; @@ -981,40 +981,40 @@ public void run() { } } } - + private static class ServiceKey { - + private String namespaceId; - + private String serviceName; - + private String serverIP; - + private String checksum; - + public String getChecksum() { return checksum; } - + public String getServerIP() { return serverIP; } - + public String getServiceName() { return serviceName; } - + public String getNamespaceId() { return namespaceId; } - + public ServiceKey(String namespaceId, String serviceName, String serverIP, String checksum) { this.namespaceId = namespaceId; this.serviceName = serviceName; this.serverIP = serverIP; this.checksum = checksum; } - + @Override public String toString() { return JacksonUtils.toJson(this); From a56c550d8afe45febb7b77f93dd03ee0645c96e9 Mon Sep 17 00:00:00 2001 From: pengzhengfa <13656694002@163.com> Date: Thu, 18 Jun 2020 13:13:08 +0800 Subject: [PATCH 4/6] Solve code space problem --- .../consistency/ConsistencyService.java | 12 +- .../DelegateConsistencyServiceImpl.java | 24 +- .../distro/DistroConsistencyServiceImpl.java | 150 +++--- .../raft/RaftConsistencyServiceImpl.java | 24 +- .../consistency/persistent/raft/RaftCore.java | 450 +++++++++--------- .../controllers/InstanceController.java | 202 ++++---- .../alibaba/nacos/naming/core/Cluster.java | 147 +++--- .../nacos/naming/core/ServiceManager.java | 364 +++++++------- 8 files changed, 687 insertions(+), 686 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/ConsistencyService.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/ConsistencyService.java index ae4519839fc..ae27e97bc5c 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/ConsistencyService.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/ConsistencyService.java @@ -32,7 +32,7 @@ * @since 1.0.0 */ public interface ConsistencyService { - + /** * Put a data related to a key to Nacos cluster. * @@ -41,7 +41,7 @@ public interface ConsistencyService { * @throws NacosException nacos exception */ void put(String key, Record value) throws NacosException; - + /** * Remove a data from Nacos cluster. * @@ -49,7 +49,7 @@ public interface ConsistencyService { * @throws NacosException nacos exception */ void remove(String key) throws NacosException; - + /** * Get a data from Nacos cluster. * @@ -58,7 +58,7 @@ public interface ConsistencyService { * @throws NacosException nacos exception */ Datum get(String key) throws NacosException; - + /** * Listen for changes of a data. * @@ -67,7 +67,7 @@ public interface ConsistencyService { * @throws NacosException nacos exception */ void listen(String key, RecordListener listener) throws NacosException; - + /** * Cancel listening of a data. * @@ -76,7 +76,7 @@ public interface ConsistencyService { * @throws NacosException nacos exception */ void unListen(String key, RecordListener listener) throws NacosException; - + /** * Tell the status of this consistency service. * diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/DelegateConsistencyServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/DelegateConsistencyServiceImpl.java index bae2f76dc67..8ff8e916394 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/DelegateConsistencyServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/DelegateConsistencyServiceImpl.java @@ -32,55 +32,55 @@ @DependsOn("ProtocolManager") @Service("consistencyDelegate") public class DelegateConsistencyServiceImpl implements ConsistencyService { - + private final PersistentConsistencyService persistentConsistencyService; - + private final EphemeralConsistencyService ephemeralConsistencyService; - + public DelegateConsistencyServiceImpl(PersistentConsistencyService persistentConsistencyService, EphemeralConsistencyService ephemeralConsistencyService) { this.persistentConsistencyService = persistentConsistencyService; this.ephemeralConsistencyService = ephemeralConsistencyService; } - + @Override public void put(String key, Record value) throws NacosException { mapConsistencyService(key).put(key, value); } - + @Override public void remove(String key) throws NacosException { mapConsistencyService(key).remove(key); } - + @Override public Datum get(String key) throws NacosException { return mapConsistencyService(key).get(key); } - + @Override public void listen(String key, RecordListener listener) throws NacosException { - + // this special key is listened by both: if (KeyBuilder.SERVICE_META_KEY_PREFIX.equals(key)) { persistentConsistencyService.listen(key, listener); ephemeralConsistencyService.listen(key, listener); return; } - + mapConsistencyService(key).listen(key, listener); } - + @Override public void unListen(String key, RecordListener listener) throws NacosException { mapConsistencyService(key).unListen(key, listener); } - + @Override public boolean isAvailable() { return ephemeralConsistencyService.isAvailable() && persistentConsistencyService.isAvailable(); } - + private ConsistencyService mapConsistencyService(String key) { return KeyBuilder.matchEphemeralKey(key) ? ephemeralConsistencyService : persistentConsistencyService; } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/DistroConsistencyServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/DistroConsistencyServiceImpl.java index 29c60b4712b..572f7c9566f 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/DistroConsistencyServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/ephemeral/distro/DistroConsistencyServiceImpl.java @@ -67,31 +67,31 @@ @DependsOn("ProtocolManager") @org.springframework.stereotype.Service("distroConsistencyService") public class DistroConsistencyServiceImpl implements EphemeralConsistencyService { - + private final DistroMapper distroMapper; - + private final DataStore dataStore; - + private final TaskDispatcher taskDispatcher; - + private final Serializer serializer; - + private final ServerMemberManager memberManager; - + private final SwitchDomain switchDomain; - + private final GlobalConfig globalConfig; - + private boolean initialized = false; - + private volatile Notifier notifier = new Notifier(); - + private LoadDataTask loadDataTask = new LoadDataTask(); - + private Map> listeners = new ConcurrentHashMap<>(); - + private Map syncChecksumTasks = new ConcurrentHashMap<>(16); - + public DistroConsistencyServiceImpl(DistroMapper distroMapper, DataStore dataStore, TaskDispatcher taskDispatcher, Serializer serializer, ServerMemberManager memberManager, SwitchDomain switchDomain, GlobalConfig globalConfig) { @@ -103,15 +103,15 @@ public DistroConsistencyServiceImpl(DistroMapper distroMapper, DataStore dataSto this.switchDomain = switchDomain; this.globalConfig = globalConfig; } - + @PostConstruct public void init() { GlobalExecutor.submit(loadDataTask); GlobalExecutor.submitDistroNotifyTask(notifier); } - + private class LoadDataTask implements Runnable { - + @Override public void run() { try { @@ -126,7 +126,7 @@ public void run() { } } } - + private void load() throws Exception { if (ApplicationUtils.getStandaloneMode()) { initialized = true; @@ -137,7 +137,7 @@ private void load() throws Exception { Thread.sleep(1000L); Loggers.DISTRO.info("waiting server list init..."); } - + for (Map.Entry entry : memberManager.getServerList().entrySet()) { final String address = entry.getValue().getAddress(); if (ApplicationUtils.getLocalAddress().equals(address)) { @@ -153,24 +153,24 @@ private void load() throws Exception { } } } - + @Override public void put(String key, Record value) throws NacosException { onPut(key, value); taskDispatcher.addTask(key); } - + @Override public void remove(String key) throws NacosException { onRemove(key); listeners.remove(key); } - + @Override public Datum get(String key) throws NacosException { return dataStore.get(key); } - + /** * Put a new record. * @@ -178,7 +178,7 @@ public Datum get(String key) throws NacosException { * @param value record */ public void onPut(String key, Record value) { - + if (KeyBuilder.matchEphemeralInstanceListKey(key)) { Datum datum = new Datum<>(); datum.value = (Instances) value; @@ -186,30 +186,30 @@ public void onPut(String key, Record value) { datum.timestamp.incrementAndGet(); dataStore.put(key, datum); } - + if (!listeners.containsKey(key)) { return; } - + notifier.addTask(key, ApplyAction.CHANGE); } - + /** * Remove a record. * * @param key key of record */ public void onRemove(String key) { - + dataStore.remove(key); - + if (!listeners.containsKey(key)) { return; } - + notifier.addTask(key, ApplyAction.DELETE); } - + /** * Check sum when receive checksums request. * @@ -217,17 +217,17 @@ public void onRemove(String key) { * @param server source server request checksum */ public void onReceiveChecksums(Map checksumMap, String server) { - + if (syncChecksumTasks.containsKey(server)) { // Already in process of this server: Loggers.DISTRO.warn("sync checksum task already in process with {}", server); return; } - + syncChecksumTasks.put(server, "1"); - + try { - + List toUpdateKeys = new ArrayList<>(); List toRemoveKeys = new ArrayList<>(); for (Map.Entry entry : checksumMap.entrySet()) { @@ -237,35 +237,35 @@ public void onReceiveChecksums(Map checksumMap, String server) { // abort the procedure: return; } - + if (!dataStore.contains(entry.getKey()) || dataStore.get(entry.getKey()).value == null || !dataStore .get(entry.getKey()).value.getChecksum().equals(entry.getValue())) { toUpdateKeys.add(entry.getKey()); } } - + for (String key : dataStore.keys()) { - + if (!server.equals(distroMapper.mapSrv(KeyBuilder.getServiceName(key)))) { continue; } - + if (!checksumMap.containsKey(key)) { toRemoveKeys.add(key); } } - + Loggers.DISTRO .info("to remove keys: {}, to update keys: {}, source: {}", toRemoveKeys, toUpdateKeys, server); - + for (String key : toRemoveKeys) { onRemove(key); } - + if (toUpdateKeys.isEmpty()) { return; } - + try { byte[] result = NamingProxy.getData(toUpdateKeys, server); processData(result); @@ -277,9 +277,9 @@ public void onReceiveChecksums(Map checksumMap, String server) { syncChecksumTasks.remove(server); } } - + private boolean syncAllDataFromRemote(String server) { - + try { byte[] data = NamingProxy.getAllData(server); return processData(data); @@ -288,14 +288,14 @@ private boolean syncAllDataFromRemote(String server) { return false; } } - + private boolean processData(byte[] data) throws Exception { if (data.length > 0) { Map> datumMap = serializer.deserializeMap(data, Instances.class); - + for (Map.Entry> entry : datumMap.entrySet()) { dataStore.put(entry.getKey(), entry.getValue()); - + if (!listeners.containsKey(entry.getKey())) { // pretty sure the service not exist: if (switchDomain.isDefaultInstanceEphemeral()) { @@ -310,7 +310,7 @@ private boolean processData(byte[] data) throws Exception { // now validate the service. if failed, exception will be thrown service.setLastModifiedMillis(System.currentTimeMillis()); service.recalculateChecksum(); - + // The Listener corresponding to the key value must not be empty RecordListener listener = listeners.get(KeyBuilder.SERVICE_META_KEY_PREFIX).peek(); if (Objects.isNull(listener)) { @@ -320,15 +320,15 @@ private boolean processData(byte[] data) throws Exception { } } } - + for (Map.Entry> entry : datumMap.entrySet()) { - + if (!listeners.containsKey(entry.getKey())) { // Should not happen: Loggers.DISTRO.warn("listener of {} not found.", entry.getKey()); continue; } - + try { for (RecordListener listener : listeners.get(entry.getKey())) { listener.onChange(entry.getKey(), entry.getValue().value); @@ -337,27 +337,27 @@ private boolean processData(byte[] data) throws Exception { Loggers.DISTRO.error("[NACOS-DISTRO] error while execute listener of key: {}", entry.getKey(), e); continue; } - + // Update data store if listener executed successfully: dataStore.put(entry.getKey(), entry.getValue()); } } return true; } - + @Override public void listen(String key, RecordListener listener) throws NacosException { if (!listeners.containsKey(key)) { listeners.put(key, new ConcurrentLinkedQueue<>()); } - + if (listeners.get(key).contains(listener)) { return; } - + listeners.get(key).add(listener); } - + @Override public void unListen(String key, RecordListener listener) throws NacosException { if (!listeners.containsKey(key)) { @@ -370,22 +370,22 @@ public void unListen(String key, RecordListener listener) throws NacosException } } } - + @Override public boolean isAvailable() { return isInitialized() || ServerStatus.UP.name().equals(switchDomain.getOverriddenServerStatus()); } - + public boolean isInitialized() { return initialized || !globalConfig.isDataWarmup(); } - + public class Notifier implements Runnable { - + private ConcurrentHashMap services = new ConcurrentHashMap<>(10 * 1024); - + private BlockingQueue> tasks = new ArrayBlockingQueue<>(1024 * 1024); - + /** * Add new notify task to queue. * @@ -393,7 +393,7 @@ public class Notifier implements Runnable { * @param action action for data */ public void addTask(String datumKey, ApplyAction action) { - + if (services.containsKey(datumKey) && action == ApplyAction.CHANGE) { return; } @@ -402,15 +402,15 @@ public void addTask(String datumKey, ApplyAction action) { } tasks.offer(Pair.with(datumKey, action)); } - + public int getTaskSize() { return tasks.size(); } - + @Override public void run() { Loggers.DISTRO.info("distro notifier started"); - + for (; ; ) { try { Pair pair = tasks.take(); @@ -420,30 +420,30 @@ public void run() { } } } - + private void handle(Pair pair) { try { String datumKey = pair.getValue0(); ApplyAction action = pair.getValue1(); - + services.remove(datumKey); - + int count = 0; - + if (!listeners.containsKey(datumKey)) { return; } - + for (RecordListener listener : listeners.get(datumKey)) { - + count++; - + try { if (action == ApplyAction.CHANGE) { listener.onChange(datumKey, dataStore.get(datumKey).value); continue; } - + if (action == ApplyAction.DELETE) { listener.onDelete(datumKey); continue; @@ -452,7 +452,7 @@ private void handle(Pair pair) { 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: {}", diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java index b0442add46b..89ca241b4f1 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java @@ -38,16 +38,16 @@ @DependsOn("ProtocolManager") @Service public class RaftConsistencyServiceImpl implements PersistentConsistencyService { - + @Autowired private RaftCore raftCore; - + @Autowired private RaftPeerSet peers; - + @Autowired private SwitchDomain switchDomain; - + @Override public void put(String key, Record value) throws NacosException { try { @@ -58,7 +58,7 @@ public void put(String key, Record value) throws NacosException { e); } } - + @Override public void remove(String key) throws NacosException { try { @@ -76,27 +76,27 @@ public void remove(String key) throws NacosException { throw new NacosException(NacosException.SERVER_ERROR, "Raft remove failed, key:" + key, e); } } - + @Override public Datum get(String key) throws NacosException { return raftCore.getDatum(key); } - + @Override public void listen(String key, RecordListener listener) throws NacosException { raftCore.listen(key, listener); } - + @Override public void unListen(String key, RecordListener listener) throws NacosException { - raftCore.unListen(key, listener); + raftCore.unlisten(key, listener); } - + @Override public boolean isAvailable() { return raftCore.isInitialized() || ServerStatus.UP.name().equals(switchDomain.getOverriddenServerStatus()); } - + /** * Put a new datum from other server. * @@ -113,7 +113,7 @@ public void onPut(Datum datum, RaftPeer source) throws NacosException { "Raft onPut failed, datum:" + datum + ", source: " + source, e); } } - + /** * Remove a new datum from other server. * diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java index b38dea638d1..7ec7f8fa9b9 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java @@ -82,62 +82,62 @@ @DependsOn("ProtocolManager") @Component public class RaftCore { - + public static final String API_VOTE = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/vote"; - + public static final String API_BEAT = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/beat"; - + public static final String API_PUB = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/datum"; - + public static final String API_DEL = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/datum"; - + public static final String API_GET = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/datum"; - + public static final String API_ON_PUB = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/datum/commit"; - + public static final String API_ON_DEL = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/datum/commit"; - + public static final String API_GET_PEER = UtilsAndCommons.NACOS_NAMING_CONTEXT + "/raft/peer"; - + private final ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1, new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); - + t.setDaemon(true); t.setName("com.alibaba.nacos.naming.raft.notifier"); - + return t; } }); - + public static final Lock OPERATE_LOCK = new ReentrantLock(); - + public static final int PUBLISH_TERM_INCREASE_COUNT = 100; - + private volatile ConcurrentMap> listeners = new ConcurrentHashMap<>(); - + private volatile ConcurrentMap datums = new ConcurrentHashMap<>(); - + @Autowired private RaftPeerSet peers; - + @Autowired private SwitchDomain switchDomain; - + @Autowired private GlobalConfig globalConfig; - + @Autowired private RaftProxy raftProxy; - + @Autowired private RaftStore raftStore; - + public volatile Notifier notifier = new Notifier(); - + private boolean initialized = false; - + /** * Init raft core. * @@ -145,41 +145,41 @@ public Thread newThread(Runnable r) { */ @PostConstruct public void init() throws Exception { - + Loggers.RAFT.info("initializing Raft sub-system"); - + executor.submit(notifier); - + final long start = System.currentTimeMillis(); - + raftStore.loadDatums(notifier, datums); - + setTerm(NumberUtils.toLong(raftStore.loadMeta().getProperty("term"), 0L)); - + Loggers.RAFT.info("cache loaded, datum count: {}, current term: {}", datums.size(), peers.getTerm()); - + while (true) { if (notifier.tasks.size() <= 0) { break; } Thread.sleep(1000L); } - + initialized = true; - + Loggers.RAFT.info("finish to load data from disk, cost: {} ms.", (System.currentTimeMillis() - start)); - + GlobalExecutor.registerMasterElection(new MasterElection()); GlobalExecutor.registerHeartbeat(new HeartBeat()); - + Loggers.RAFT.info("timer started: leader timeout ms: {}, heart-beat timeout ms: {}", GlobalExecutor.LEADER_TIMEOUT_MS, GlobalExecutor.HEARTBEAT_INTERVAL_MS); } - + public Map> getListeners() { return listeners; } - + /** * Signal publish new record. If not leader, signal to leader. If leader, try to commit publish. * @@ -188,20 +188,20 @@ public Map> getListeners() { * @throws Exception any exception during publish */ public void signalPublish(String key, Record value) throws Exception { - + if (!isLeader()) { ObjectNode params = JacksonUtils.createEmptyJsonNode(); params.put("key", key); params.replace("value", JacksonUtils.transferToJsonNode(value)); Map parameters = new HashMap<>(1); parameters.put("key", key); - + final RaftPeer leader = getLeader(); - + raftProxy.proxyPostLarge(leader.ip, API_PUB, params.toString(), parameters); return; } - + try { OPERATE_LOCK.lock(); final long start = System.currentTimeMillis(); @@ -213,15 +213,15 @@ public void signalPublish(String key, Record value) throws Exception { } else { datum.timestamp.set(getDatum(key).timestamp.incrementAndGet()); } - + ObjectNode json = JacksonUtils.createEmptyJsonNode(); json.replace("datum", JacksonUtils.transferToJsonNode(datum)); json.replace("source", JacksonUtils.transferToJsonNode(peers.local())); - + onPublish(datum, peers.local()); - + final String content = json.toString(); - + final CountDownLatch latch = new CountDownLatch(peers.majorityCount()); for (final String server : peers.allServersIncludeMyself()) { if (isLeader(server)) { @@ -242,28 +242,28 @@ public Integer onCompleted(Response response) throws Exception { latch.countDown(); return 0; } - + @Override public STATE onContentWriteCompleted() { return STATE.CONTINUE; } }); - + } - + if (!latch.await(UtilsAndCommons.RAFT_PUBLISH_TIMEOUT, TimeUnit.MILLISECONDS)) { // only majority servers return success can we consider this update success Loggers.RAFT.error("data publish failed, caused failed to notify majority, key={}", key); throw new IllegalStateException("data publish failed, caused failed to notify majority, key=" + key); } - + long end = System.currentTimeMillis(); Loggers.RAFT.info("signalPublish cost {} ms, key: {}", (end - start), key); } finally { OPERATE_LOCK.unlock(); } } - + /** * Signal delete record. If not leader, signal leader delete. If leader, try to commit delete. * @@ -271,26 +271,26 @@ public STATE onContentWriteCompleted() { * @throws Exception any exception during delete */ public void signalDelete(final String key) throws Exception { - + OPERATE_LOCK.lock(); try { - + if (!isLeader()) { Map params = new HashMap<>(1); params.put("key", URLEncoder.encode(key, "UTF-8")); raftProxy.proxy(getLeader().ip, API_DEL, params, HttpMethod.DELETE); return; } - + // construct datum: Datum datum = new Datum(); datum.key = key; ObjectNode json = JacksonUtils.createEmptyJsonNode(); json.replace("datum", JacksonUtils.transferToJsonNode(datum)); json.replace("source", JacksonUtils.transferToJsonNode(peers.local())); - + onDelete(datum.key, peers.local()); - + for (final String server : peers.allServersWithoutMySelf()) { String url = buildUrl(server, API_ON_DEL); HttpClient.asyncHttpDeleteLarge(url, null, json.toString(), new AsyncCompletionHandler() { @@ -302,11 +302,11 @@ public Integer onCompleted(Response response) throws Exception { key, server, response.getStatusCode()); return 1; } - + RaftPeer local = peers.local(); - + local.resetLeaderDue(); - + return 0; } }); @@ -315,7 +315,7 @@ public Integer onCompleted(Response response) throws Exception { OPERATE_LOCK.unlock(); } } - + /** * Do publish. If leader, commit publish to store. If not leader, stop publish because should signal to leader. * @@ -329,30 +329,30 @@ public void onPublish(Datum datum, RaftPeer source) throws Exception { Loggers.RAFT.warn("received empty datum"); throw new IllegalStateException("received empty datum"); } - + if (!peers.isLeader(source.ip)) { Loggers.RAFT .warn("peer {} tried to publish data but wasn't leader, leader: {}", JacksonUtils.toJson(source), JacksonUtils.toJson(getLeader())); throw new IllegalStateException("peer(" + source.ip + ") tried to publish " + "data but wasn't leader"); } - + if (source.term.get() < local.term.get()) { Loggers.RAFT.warn("out of date publish, pub-term: {}, cur-term: {}", JacksonUtils.toJson(source), JacksonUtils.toJson(local)); throw new IllegalStateException( "out of date publish, pub-term:" + source.term.get() + ", cur-term: " + local.term.get()); } - + local.resetLeaderDue(); - + // if data should be persisted, usually this is true: if (KeyBuilder.matchPersistentKey(datum.key)) { raftStore.write(datum); } - + datums.put(datum.key, datum); - + if (isLeader()) { local.term.addAndGet(PUBLISH_TERM_INCREASE_COUNT); } else { @@ -365,12 +365,12 @@ public void onPublish(Datum datum, RaftPeer source) throws Exception { } } raftStore.updateTerm(local.term.get()); - + notifier.addTask(datum.key, ApplyAction.CHANGE); - + Loggers.RAFT.info("data added/updated, key={}, term={}", datum.key, local.term); } - + /** * Do delete. If leader, commit delete to store. If not leader, stop delete because should signal to leader. * @@ -379,31 +379,31 @@ public void onPublish(Datum datum, RaftPeer source) throws Exception { * @throws Exception any exception during delete */ public void onDelete(String datumKey, RaftPeer source) throws Exception { - + RaftPeer local = peers.local(); - + if (!peers.isLeader(source.ip)) { Loggers.RAFT .warn("peer {} tried to publish data but wasn't leader, leader: {}", JacksonUtils.toJson(source), JacksonUtils.toJson(getLeader())); throw new IllegalStateException("peer(" + source.ip + ") tried to publish data but wasn't leader"); } - + if (source.term.get() < local.term.get()) { Loggers.RAFT.warn("out of date publish, pub-term: {}, cur-term: {}", JacksonUtils.toJson(source), JacksonUtils.toJson(local)); throw new IllegalStateException( "out of date publish, pub-term:" + source.term + ", cur-term: " + local.term); } - + local.resetLeaderDue(); - + // do apply String key = datumKey; deleteDatum(key); - + if (KeyBuilder.matchServiceMetaKey(key)) { - + if (local.term.get() + PUBLISH_TERM_INCREASE_COUNT > source.term.get()) { //set leader term: getLeader().term.set(source.term.get()); @@ -411,54 +411,54 @@ public void onDelete(String datumKey, RaftPeer source) throws Exception { } else { local.term.addAndGet(PUBLISH_TERM_INCREASE_COUNT); } - + raftStore.updateTerm(local.term.get()); } - + Loggers.RAFT.info("data removed, key={}, term={}", datumKey, local.term); - + } - + public class MasterElection implements Runnable { - + @Override public void run() { try { - + if (!peers.isReady()) { return; } - + RaftPeer local = peers.local(); local.leaderDueMs -= GlobalExecutor.TICK_PERIOD_MS; - + if (local.leaderDueMs > 0) { return; } - + // reset timeout local.resetLeaderDue(); local.resetHeartbeatDue(); - + sendVote(); } catch (Exception e) { Loggers.RAFT.warn("[RAFT] error while master election {}", e); } - + } - + private void sendVote() { - + RaftPeer local = peers.get(NetUtils.localServer()); Loggers.RAFT.info("leader timeout, start voting,leader: {}, term: {}", JacksonUtils.toJson(getLeader()), local.term); - + peers.reset(); - + local.term.incrementAndGet(); local.voteFor = local.ip; local.state = RaftPeer.State.CANDIDATE; - + Map params = new HashMap<>(1); params.put("vote", JacksonUtils.toJson(local)); for (final String server : peers.allServersWithoutMySelf()) { @@ -472,13 +472,13 @@ public Integer onCompleted(Response response) throws Exception { .error("NACOS-RAFT vote failed: {}, url: {}", response.getResponseBody(), url); return 1; } - + RaftPeer peer = JacksonUtils.toObj(response.getResponseBody(), RaftPeer.class); - + Loggers.RAFT.info("received approve from peer: {}", JacksonUtils.toJson(peer)); - + peers.decideLeader(peer); - + return 0; } }); @@ -488,7 +488,7 @@ public Integer onCompleted(Response response) throws Exception { } } } - + /** * Received vote. * @@ -499,55 +499,55 @@ public synchronized RaftPeer receivedVote(RaftPeer remote) { if (!peers.contains(remote)) { throw new IllegalStateException("can not find peer: " + remote.ip); } - + RaftPeer local = peers.get(NetUtils.localServer()); if (remote.term.get() <= local.term.get()) { String msg = "received illegitimate vote" + ", voter-term:" + remote.term + ", votee-term:" + local.term; - + Loggers.RAFT.info(msg); if (StringUtils.isEmpty(local.voteFor)) { local.voteFor = local.ip; } - + return local; } - + local.resetLeaderDue(); - + local.state = RaftPeer.State.FOLLOWER; local.voteFor = remote.ip; local.term.set(remote.term.get()); - + Loggers.RAFT.info("vote {} as leader, term: {}", remote.ip, remote.term); - + return local; } - + public class HeartBeat implements Runnable { - + @Override public void run() { try { - + if (!peers.isReady()) { return; } - + RaftPeer local = peers.local(); local.heartbeatDueMs -= GlobalExecutor.TICK_PERIOD_MS; if (local.heartbeatDueMs > 0) { return; } - + local.resetHeartbeatDue(); - + sendBeat(); } catch (Exception e) { Loggers.RAFT.warn("[RAFT] error while sending beat {}", e); } - + } - + private void sendBeat() throws IOException, InterruptedException { RaftPeer local = peers.local(); if (ApplicationUtils.getStandaloneMode() || local.state != RaftPeer.State.LEADER) { @@ -556,55 +556,55 @@ private void sendBeat() throws IOException, InterruptedException { if (Loggers.RAFT.isDebugEnabled()) { Loggers.RAFT.debug("[RAFT] send beat with {} keys.", datums.size()); } - + local.resetLeaderDue(); - + // build data ObjectNode packet = JacksonUtils.createEmptyJsonNode(); packet.replace("peer", JacksonUtils.transferToJsonNode(local)); - + ArrayNode array = JacksonUtils.createEmptyArrayNode(); - + if (switchDomain.isSendBeatOnly()) { Loggers.RAFT.info("[SEND-BEAT-ONLY] {}", String.valueOf(switchDomain.isSendBeatOnly())); } - + if (!switchDomain.isSendBeatOnly()) { for (Datum datum : datums.values()) { - + ObjectNode element = JacksonUtils.createEmptyJsonNode(); - + if (KeyBuilder.matchServiceMetaKey(datum.key)) { element.put("key", KeyBuilder.briefServiceMetaKey(datum.key)); } else if (KeyBuilder.matchInstanceListKey(datum.key)) { element.put("key", KeyBuilder.briefInstanceListkey(datum.key)); } element.put("timestamp", datum.timestamp.get()); - + array.add(element); } } - + packet.replace("datums", array); // broadcast Map params = new HashMap(1); params.put("beat", JacksonUtils.toJson(packet)); - + String content = JacksonUtils.toJson(params); - + ByteArrayOutputStream out = new ByteArrayOutputStream(); GZIPOutputStream gzip = new GZIPOutputStream(out); gzip.write(content.getBytes(StandardCharsets.UTF_8)); gzip.close(); - + byte[] compressedBytes = out.toByteArray(); String compressedContent = new String(compressedBytes, StandardCharsets.UTF_8); - + if (Loggers.RAFT.isDebugEnabled()) { Loggers.RAFT.debug("raw beat data size: {}, size of compressed data: {}", content.length(), compressedContent.length()); } - + for (final String server : peers.allServersWithoutMySelf()) { try { final String url = buildUrl(server, API_BEAT); @@ -620,14 +620,14 @@ public Integer onCompleted(Response response) throws Exception { MetricsMonitor.getLeaderSendBeatFailedException().increment(); return 1; } - + peers.update(JacksonUtils.toObj(response.getResponseBody(), RaftPeer.class)); if (Loggers.RAFT.isDebugEnabled()) { Loggers.RAFT.debug("receive beat response from: {}", url); } return 0; } - + @Override public void onThrowable(Throwable t) { Loggers.RAFT.error("NACOS-RAFT error while sending heart-beat to peer: {} {}", server, t); @@ -639,10 +639,10 @@ public void onThrowable(Throwable t) { MetricsMonitor.getLeaderSendBeatFailedException().increment(); } } - + } } - + /** * Received beat from leader. // TODO split method to multiple smaller method. * @@ -660,13 +660,13 @@ public RaftPeer receivedBeat(JsonNode beat) throws Exception { remote.heartbeatDueMs = peer.get("heartbeatDueMs").asLong(); remote.leaderDueMs = peer.get("leaderDueMs").asLong(); remote.voteFor = peer.get("voteFor").asText(); - + if (remote.state != RaftPeer.State.LEADER) { Loggers.RAFT.info("[RAFT] invalid state from master, state: {}, remote peer: {}", remote.state, JacksonUtils.toJson(remote)); throw new IllegalArgumentException("invalid state from master, state: " + remote.state); } - + if (local.term.get() > remote.term.get()) { Loggers.RAFT .info("[RAFT] out of date beat, beat-from-term: {}, beat-to-term: {}, remote peer: {}, and leaderDueMs: {}", @@ -674,32 +674,32 @@ public RaftPeer receivedBeat(JsonNode beat) throws Exception { throw new IllegalArgumentException( "out of date beat, beat-from-term: " + remote.term.get() + ", beat-to-term: " + local.term.get()); } - + if (local.state != RaftPeer.State.FOLLOWER) { - + Loggers.RAFT.info("[RAFT] make remote as leader, remote peer: {}", JacksonUtils.toJson(remote)); // mk follower local.state = RaftPeer.State.FOLLOWER; local.voteFor = remote.ip; } - + final JsonNode beatDatums = beat.get("datums"); local.resetLeaderDue(); local.resetHeartbeatDue(); - + peers.makeLeader(remote); - + if (!switchDomain.isSendBeatOnly()) { - + Map receivedKeysMap = new HashMap<>(datums.size()); - + for (Map.Entry entry : datums.entrySet()) { receivedKeysMap.put(entry.getKey(), 0); } - + // now check datums List batch = new ArrayList<>(); - + int processedCount = 0; if (Loggers.RAFT.isDebugEnabled()) { Loggers.RAFT @@ -708,11 +708,11 @@ public RaftPeer receivedBeat(JsonNode beat) throws Exception { } for (Object object : beatDatums) { processedCount = processedCount + 1; - + JsonNode entry = (JsonNode) object; String key = entry.get("key").asText(); final String datumKey; - + if (KeyBuilder.matchServiceMetaKey(key)) { datumKey = KeyBuilder.detailServiceMetaKey(key); } else if (KeyBuilder.matchInstanceListKey(key)) { @@ -721,35 +721,35 @@ public RaftPeer receivedBeat(JsonNode beat) throws Exception { // ignore corrupted key: continue; } - + long timestamp = entry.get("timestamp").asLong(); - + receivedKeysMap.put(datumKey, 1); - + try { if (datums.containsKey(datumKey) && datums.get(datumKey).timestamp.get() >= timestamp && processedCount < beatDatums.size()) { continue; } - + if (!(datums.containsKey(datumKey) && datums.get(datumKey).timestamp.get() >= timestamp)) { batch.add(datumKey); } - + if (batch.size() < 50 && processedCount < beatDatums.size()) { continue; } - + String keys = StringUtils.join(batch, ","); - + if (batch.size() <= 0) { continue; } - + Loggers.RAFT.info("get datums from leader: {}, batch size is {}, processedCount is {}" + ", datums' size is {}, RaftCore.datums' size is {}", getLeader().ip, batch.size(), processedCount, beatDatums.size(), datums.size()); - + // update datum entry String url = buildUrl(remote.ip, API_GET) + "?keys=" + URLEncoder.encode(keys, "UTF-8"); HttpClient.asyncHttpGet(url, null, null, new AsyncCompletionHandler() { @@ -758,18 +758,18 @@ public Integer onCompleted(Response response) throws Exception { if (response.getStatusCode() != HttpURLConnection.HTTP_OK) { return 1; } - + List datumList = JacksonUtils .toObj(response.getResponseBody(), new TypeReference>() { }); - + for (JsonNode datumJson : datumList) { Datum newDatum = null; OPERATE_LOCK.lock(); try { - + Datum oldDatum = getDatum(datumJson.get("key").asText()); - + if (oldDatum != null && datumJson.get("timestamp").asLong() <= oldDatum.timestamp .get()) { Loggers.RAFT @@ -778,7 +778,7 @@ public Integer onCompleted(Response response) throws Exception { datumJson.get("timestamp").asLong(), oldDatum.timestamp); continue; } - + if (KeyBuilder.matchServiceMetaKey(datumJson.get("key").asText())) { Datum serviceDatum = new Datum<>(); serviceDatum.key = datumJson.get("key").asText(); @@ -787,7 +787,7 @@ public Integer onCompleted(Response response) throws Exception { .toObj(datumJson.get("value").toString(), Service.class); newDatum = serviceDatum; } - + if (KeyBuilder.matchInstanceListKey(datumJson.get("key").asText())) { Datum instancesDatum = new Datum<>(); instancesDatum.key = datumJson.get("key").asText(); @@ -796,31 +796,31 @@ public Integer onCompleted(Response response) throws Exception { .toObj(datumJson.get("value").toString(), Instances.class); newDatum = instancesDatum; } - + if (newDatum == null || newDatum.value == null) { Loggers.RAFT.error("receive null datum: {}", datumJson); continue; } - + raftStore.write(newDatum); - + datums.put(newDatum.key, newDatum); notifier.addTask(newDatum.key, ApplyAction.CHANGE); - + local.resetLeaderDue(); - + if (local.term.get() + 100 > remote.term.get()) { getLeader().term.set(remote.term.get()); local.term.set(getLeader().term.get()); } else { local.term.addAndGet(100); } - + raftStore.updateTerm(local.term.get()); - + Loggers.RAFT.info("data updated, key: {}, timestamp: {}, from {}, local term: {}", newDatum.key, newDatum.timestamp, JacksonUtils.toJson(remote), local.term); - + } catch (Throwable e) { Loggers.RAFT .error("[RAFT-BEAT] failed to sync datum from leader, datum: {}", newDatum, @@ -833,22 +833,22 @@ public Integer onCompleted(Response response) throws Exception { return 0; } }); - + batch.clear(); - + } catch (Exception e) { Loggers.RAFT.error("[NACOS-RAFT] failed to handle beat entry, key: {}", datumKey); } - + } - + List deadKeys = new ArrayList<>(); for (Map.Entry entry : receivedKeysMap.entrySet()) { if (entry.getValue() == 0) { deadKeys.add(entry.getKey()); } } - + for (String deadKey : deadKeys) { try { deleteDatum(deadKey); @@ -856,12 +856,12 @@ public Integer onCompleted(Response response) throws Exception { Loggers.RAFT.error("[NACOS-RAFT] failed to remove entry, key={} {}", deadKey, e); } } - + } - + return local; } - + /** * Add listener for target key. * @@ -869,27 +869,27 @@ public Integer onCompleted(Response response) throws Exception { * @param listener new listener */ public void listen(String key, RecordListener listener) { - + List listenerList = listeners.get(key); if (listenerList != null && listenerList.contains(listener)) { return; } - + if (listenerList == null) { listenerList = new CopyOnWriteArrayList<>(); listeners.put(key, listenerList); } - + Loggers.RAFT.info("add listener: {}", key); - + listenerList.add(listener); - + // if data present, notify immediately for (Datum datum : datums.values()) { if (!listener.interests(datum.key)) { continue; } - + try { listener.onChange(datum.key, datum.value); } catch (Exception e) { @@ -897,19 +897,19 @@ public void listen(String key, RecordListener listener) { } } } - + /** * Remove listener for key. * * @param key key * @param listener listener */ - public void unListen(String key, RecordListener listener) { - + public void unlisten(String key, RecordListener listener) { + if (!listeners.containsKey(key)) { return; } - + for (RecordListener dl : listeners.get(key)) { // TODO maybe use equal: if (dl == listener) { @@ -918,23 +918,23 @@ public void unListen(String key, RecordListener listener) { } } } - + public void unlistenAll(String key) { listeners.remove(key); } - + public void setTerm(long term) { peers.setTerm(term); } - + public boolean isLeader(String ip) { return peers.isLeader(ip); } - + public boolean isLeader() { return peers.isLeader(NetUtils.localServer()); } - + /** * Build api url. * @@ -948,36 +948,36 @@ public static String buildUrl(String ip, String api) { } return "http://" + ip + ApplicationUtils.getContextPath() + api; } - + public Datum getDatum(String key) { return datums.get(key); } - + public RaftPeer getLeader() { return peers.getLeader(); } - + public List getPeers() { return new ArrayList<>(peers.allPeers()); } - + public RaftPeerSet getPeerSet() { return peers; } - + public void setPeerSet(RaftPeerSet peerSet) { peers = peerSet; } - + public int datumSize() { return datums.size(); } - + public void addDatum(Datum datum) { datums.put(datum.key, datum); notifier.addTask(datum.key, ApplyAction.CHANGE); } - + /** * Load datum. * @@ -993,9 +993,9 @@ public void loadDatum(String key) { } catch (Exception e) { Loggers.RAFT.error("load datum failed: " + key, e); } - + } - + private void deleteDatum(String key) { Datum deleted; try { @@ -1009,21 +1009,21 @@ private void deleteDatum(String key) { Loggers.RAFT.warn("datum key decode failed: {}", key); } } - + public boolean isInitialized() { return initialized || !globalConfig.isDataWarmup(); } - + public int getNotifyTaskCount() { return notifier.getTaskSize(); } - + public class Notifier implements Runnable { - + private ConcurrentHashMap services = new ConcurrentHashMap<>(10 * 1024); - + private BlockingQueue tasks = new LinkedBlockingQueue<>(1024 * 1024); - + /** * Add notify task. * @@ -1031,55 +1031,55 @@ public class Notifier implements Runnable { * @param action action of datum */ public void addTask(String datumKey, ApplyAction action) { - + if (services.containsKey(datumKey) && action == ApplyAction.CHANGE) { return; } if (action == ApplyAction.CHANGE) { services.put(datumKey, StringUtils.EMPTY); } - + Loggers.RAFT.info("add task {}", datumKey); - + tasks.add(Pair.with(datumKey, action)); } - + public int getTaskSize() { return tasks.size(); } - + @Override public void run() { Loggers.RAFT.info("raft notifier started"); - + while (true) { try { - + Pair pair = tasks.take(); - + if (pair == null) { continue; } - + String datumKey = (String) pair.getValue0(); ApplyAction action = (ApplyAction) pair.getValue1(); - + services.remove(datumKey); - + Loggers.RAFT.info("remove task {}", datumKey); - + int count = 0; - + if (listeners.containsKey(KeyBuilder.SERVICE_META_KEY_PREFIX)) { - + if (KeyBuilder.matchServiceMetaKey(datumKey) && !KeyBuilder.matchSwitchKey(datumKey)) { - + for (RecordListener listener : listeners.get(KeyBuilder.SERVICE_META_KEY_PREFIX)) { try { if (action == ApplyAction.CHANGE) { listener.onChange(datumKey, getDatum(datumKey).value); } - + if (action == ApplyAction.DELETE) { listener.onDelete(datumKey); } @@ -1091,21 +1091,21 @@ public void run() { } } } - + if (!listeners.containsKey(datumKey)) { continue; } - + for (RecordListener listener : listeners.get(datumKey)) { - + count++; - + try { if (action == ApplyAction.CHANGE) { listener.onChange(datumKey, getDatum(datumKey).value); continue; } - + if (action == ApplyAction.DELETE) { listener.onDelete(datumKey); continue; @@ -1114,7 +1114,7 @@ public void run() { Loggers.RAFT.error("[NACOS-RAFT] error while notifying listener of key: {}", datumKey, e); } } - + if (Loggers.RAFT.isDebugEnabled()) { Loggers.RAFT.debug("[NACOS-RAFT] datum change notified, key: {}, listener count: {}", datumKey, count); diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java index e1159ee4ee0..0d3aecfb7b0 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/InstanceController.java @@ -71,21 +71,21 @@ @RestController @RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance") public class InstanceController { - + @Autowired private SwitchDomain switchDomain; - + @Autowired private PushService pushService; - + @Autowired private ServiceManager serviceManager; - + private DataSource pushDataSource = new DataSource() { - + @Override public String getData(PushService.PushClient client) { - + ObjectNode result = JacksonUtils.createEmptyJsonNode(); try { result = doSrvIpxt(client.getNamespaceId(), client.getServiceName(), client.getAgent(), @@ -94,14 +94,14 @@ public String getData(PushService.PushClient client) { } catch (Exception e) { Loggers.SRV_LOG.warn("PUSH-SERVICE: service is not modified", e); } - + // overdrive the cache millis to push mode result.put("cacheMillis", switchDomain.getPushCacheMillis(client.getServiceName())); - + return result.toString(); } }; - + /** * Register new instance. * @@ -113,17 +113,17 @@ public String getData(PushService.PushClient client) { @PostMapping @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE) public String register(HttpServletRequest request) throws Exception { - + final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); final String namespaceId = WebUtils .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); - + final Instance instance = parseInstance(request); - + serviceManager.registerInstance(namespaceId, serviceName, instance); return "ok"; } - + /** * Deregister instances. * @@ -138,17 +138,17 @@ public String deregister(HttpServletRequest request) throws Exception { Instance instance = getIpAddress(request); String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); - + Service service = serviceManager.getService(namespaceId, serviceName); if (service == null) { Loggers.SRV_LOG.warn("remove instance from non-exist service: {}", serviceName); return "ok"; } - + serviceManager.removeInstance(namespaceId, serviceName, instance.isEphemeral(), instance); return "ok"; } - + /** * Update instance. * @@ -164,11 +164,11 @@ public String update(HttpServletRequest request) throws Exception { final String namespaceId = WebUtils .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); final Instance instance = parseInstance(request); - + String agent = WebUtils.getUserAgent(request); - + ClientInfo clientInfo = new ClientInfo(agent); - + if (clientInfo.type == ClientInfo.ClientType.JAVA && clientInfo.version.compareTo(VersionUtil.parseVersion("1.0.0")) >= 0) { serviceManager.updateInstance(namespaceId, serviceName, instance); @@ -177,7 +177,7 @@ public String update(HttpServletRequest request) throws Exception { } return "ok"; } - + /** * Patch instance. * @@ -197,12 +197,12 @@ public String patch(HttpServletRequest request) throws Exception { if (StringUtils.isBlank(cluster)) { cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME); } - + Instance instance = serviceManager.getInstance(namespaceId, serviceName, cluster, ip, Integer.parseInt(port)); if (instance == null) { throw new IllegalArgumentException("instance not found"); } - + String metadata = WebUtils.optional(request, "metadata", StringUtils.EMPTY); if (StringUtils.isNotBlank(metadata)) { instance.setMetadata(UtilsAndCommons.parseMetadata(metadata)); @@ -228,7 +228,7 @@ public String patch(HttpServletRequest request) throws Exception { serviceManager.updateInstance(namespaceId, serviceName, instance); return "ok"; } - + /** * Get all instance of input service. * @@ -239,9 +239,9 @@ public String patch(HttpServletRequest request) throws Exception { @GetMapping("/list") @Secured(parser = NamingResourceParser.class, action = ActionTypes.READ) public ObjectNode list(HttpServletRequest request) throws Exception { - + String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); - + String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); String agent = WebUtils.getUserAgent(request); String clusters = WebUtils.optional(request, "clusters", StringUtils.EMPTY); @@ -249,17 +249,17 @@ public ObjectNode list(HttpServletRequest request) throws Exception { int udpPort = Integer.parseInt(WebUtils.optional(request, "udpPort", "0")); String env = WebUtils.optional(request, "env", StringUtils.EMPTY); boolean isCheck = Boolean.parseBoolean(WebUtils.optional(request, "isCheck", "false")); - + String app = WebUtils.optional(request, "app", StringUtils.EMPTY); - + String tenant = WebUtils.optional(request, "tid", StringUtils.EMPTY); - + boolean healthyOnly = Boolean.parseBoolean(WebUtils.optional(request, "healthyOnly", "false")); - + return doSrvIpxt(namespaceId, serviceName, agent, clusters, clientIP, udpPort, env, isCheck, app, tenant, healthyOnly); } - + /** * Get detail information of specified instance. * @@ -270,27 +270,27 @@ public ObjectNode list(HttpServletRequest request) throws Exception { @GetMapping @Secured(parser = NamingResourceParser.class, action = ActionTypes.READ) public ObjectNode detail(HttpServletRequest request) throws Exception { - + String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); String cluster = WebUtils.optional(request, CommonParams.CLUSTER_NAME, UtilsAndCommons.DEFAULT_CLUSTER_NAME); String ip = WebUtils.required(request, "ip"); int port = Integer.parseInt(WebUtils.required(request, "port")); - + Service service = serviceManager.getService(namespaceId, serviceName); if (service == null) { throw new NacosException(NacosException.NOT_FOUND, "no service " + serviceName + " found!"); } - + List clusters = new ArrayList<>(); clusters.add(cluster); - + List ips = service.allIPs(clusters); if (ips == null || ips.isEmpty()) { throw new NacosException(NacosException.NOT_FOUND, "no ips found for cluster " + cluster + " in service " + serviceName); } - + for (Instance instance : ips) { if (instance.getIp().equals(ip) && instance.getPort() == port) { ObjectNode result = JacksonUtils.createEmptyJsonNode(); @@ -305,10 +305,10 @@ public ObjectNode detail(HttpServletRequest request) throws Exception { return result; } } - + throw new NacosException(NacosException.NOT_FOUND, "no matched ip found!"); } - + /** * Create a beat for instance. * @@ -320,10 +320,10 @@ public ObjectNode detail(HttpServletRequest request) throws Exception { @PutMapping("/beat") @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE) public ObjectNode beat(HttpServletRequest request) throws Exception { - + ObjectNode result = JacksonUtils.createEmptyJsonNode(); result.put("clientBeatInterval", switchDomain.getClientBeatInterval()); - + String beat = WebUtils.optional(request, "beat", StringUtils.EMPTY); RsInfo clientBeat = null; if (StringUtils.isNotBlank(beat)) { @@ -347,16 +347,16 @@ public ObjectNode beat(HttpServletRequest request) throws Exception { String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID); Loggers.SRV_LOG.debug("[CLIENT-BEAT] full arguments: beat: {}, serviceName: {}", clientBeat, serviceName); Instance instance = serviceManager.getInstance(namespaceId, serviceName, clusterName, ip, port); - + if (instance == null) { if (clientBeat == null) { result.put(CommonParams.CODE, NamingResponseCode.RESOURCE_NOT_FOUND); return result; } - + Loggers.SRV_LOG.warn("[CLIENT-BEAT] The instance has been removed for health mechanism, " + "perform data compensation operations, beat: {}, serviceName: {}", clientBeat, serviceName); - + instance = new Instance(); instance.setPort(clientBeat.getPort()); instance.setIp(clientBeat.getIp()); @@ -366,12 +366,12 @@ public ObjectNode beat(HttpServletRequest request) throws Exception { instance.setServiceName(serviceName); instance.setInstanceId(instance.getInstanceId()); instance.setEphemeral(clientBeat.isEphemeral()); - + serviceManager.registerInstance(namespaceId, serviceName, instance); } - + Service service = serviceManager.getService(namespaceId, serviceName); - + if (service == null) { throw new NacosException(NacosException.SERVER_ERROR, "service not found: " + serviceName + "@" + namespaceId); @@ -383,13 +383,13 @@ public ObjectNode beat(HttpServletRequest request) throws Exception { clientBeat.setCluster(clusterName); } service.processClientBeat(clientBeat); - + result.put(CommonParams.CODE, NamingResponseCode.OK); result.put("clientBeatInterval", instance.getInstanceHeartBeatInterval()); result.put(SwitchEntry.LIGHT_BEAT_ENABLED, switchDomain.isLightBeatEnabled()); return result; } - + /** * List all instance with health status. * @@ -399,10 +399,10 @@ public ObjectNode beat(HttpServletRequest request) throws Exception { */ @RequestMapping("/statuses") public ObjectNode listWithHealthStatus(@RequestParam String key) throws NacosException { - + String serviceName; String namespaceId; - + if (key.contains(UtilsAndCommons.NAMESPACE_SERVICE_CONNECTOR)) { namespaceId = key.split(UtilsAndCommons.NAMESPACE_SERVICE_CONNECTOR)[0]; serviceName = key.split(UtilsAndCommons.NAMESPACE_SERVICE_CONNECTOR)[1]; @@ -410,28 +410,28 @@ public ObjectNode listWithHealthStatus(@RequestParam String key) throws NacosExc namespaceId = Constants.DEFAULT_NAMESPACE_ID; serviceName = key; } - + Service service = serviceManager.getService(namespaceId, serviceName); - + if (service == null) { throw new NacosException(NacosException.NOT_FOUND, "service: " + serviceName + " not found."); } - + List ips = service.allIPs(); - + ObjectNode result = JacksonUtils.createEmptyJsonNode(); ArrayNode ipArray = JacksonUtils.createEmptyArrayNode(); - + for (Instance ip : ips) { ipArray.add(ip.toIpAddr() + "_" + ip.isHealthy()); } - + result.replace("ips", ipArray); return result; } - + private Instance parseInstance(HttpServletRequest request) throws Exception { - + String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME); String app = WebUtils.optional(request, "app", "DEFAULT"); Instance instance = getIpAddress(request); @@ -445,12 +445,12 @@ private Instance parseInstance(HttpServletRequest request) throws Exception { if (StringUtils.isNotEmpty(metadata)) { instance.setMetadata(UtilsAndCommons.parseMetadata(metadata)); } - + instance.validate(); - + return instance; } - + private Instance getIpAddress(HttpServletRequest request) { final String ip = WebUtils.required(request, "ip"); final String port = WebUtils.required(request, "port"); @@ -458,20 +458,20 @@ private Instance getIpAddress(HttpServletRequest request) { if (StringUtils.isBlank(cluster)) { cluster = WebUtils.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME); } - String enabledStr = WebUtils.optional(request, "enabled", StringUtils.EMPTY); + String enabledString = WebUtils.optional(request, "enabled", StringUtils.EMPTY); boolean enabled; - if (StringUtils.isBlank(enabledStr)) { + if (StringUtils.isBlank(enabledString)) { enabled = BooleanUtils.toBoolean(WebUtils.optional(request, "enable", "true")); } else { - enabled = BooleanUtils.toBoolean(enabledStr); + enabled = BooleanUtils.toBoolean(enabledString); } - + boolean ephemeral = BooleanUtils.toBoolean( WebUtils.optional(request, "ephemeral", String.valueOf(switchDomain.isDefaultInstanceEphemeral()))); - + String weight = WebUtils.optional(request, "weight", "1"); boolean healthy = BooleanUtils.toBoolean(WebUtils.optional(request, "healthy", "true")); - + Instance instance = new Instance(); instance.setPort(Integer.parseInt(port)); instance.setIp(ip); @@ -480,16 +480,16 @@ private Instance getIpAddress(HttpServletRequest request) { instance.setHealthy(healthy); instance.setEnabled(enabled); instance.setEphemeral(ephemeral); - + return instance; } - + private void checkIfDisabled(Service service) throws Exception { if (!service.getEnabled()) { throw new Exception("service is disabled now."); } } - + /** * Get service full information with instances. * @@ -509,11 +509,11 @@ private void checkIfDisabled(Service service) throws Exception { */ public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent, String clusters, String clientIP, int udpPort, String env, boolean isCheck, String app, String tid, boolean healthyOnly) throws Exception { - + ClientInfo clientInfo = new ClientInfo(agent); ObjectNode result = JacksonUtils.createEmptyJsonNode(); Service service = serviceManager.getService(namespaceId, serviceName); - + if (service == null) { if (Loggers.SRV_LOG.isDebugEnabled()) { Loggers.SRV_LOG.debug("no instance to serve for service: {}", serviceName); @@ -523,15 +523,15 @@ public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent result.replace("hosts", JacksonUtils.createEmptyArrayNode()); return result; } - + checkIfDisabled(service); - + long cacheMillis = switchDomain.getDefaultCacheMillis(); - + // now try to enable the push try { if (udpPort > 0 && pushService.canEnablePush(agent)) { - + pushService .addClient(namespaceId, serviceName, clusters, agent, new InetSocketAddress(clientIP, udpPort), pushDataSource, tid, app); @@ -542,29 +542,29 @@ public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent .error("[NACOS-API] failed to added push client {}, {}:{}", clientInfo, clientIP, udpPort, e); cacheMillis = switchDomain.getDefaultCacheMillis(); } - + List srvedIPs; - + srvedIPs = service.srvIPs(Arrays.asList(StringUtils.split(clusters, ","))); - + // filter ips using selector: if (service.getSelector() != null && StringUtils.isNotBlank(clientIP)) { srvedIPs = service.getSelector().select(clientIP, srvedIPs); } - + if (CollectionUtils.isEmpty(srvedIPs)) { - + if (Loggers.SRV_LOG.isDebugEnabled()) { Loggers.SRV_LOG.debug("no instance to serve for service: {}", serviceName); } - + if (clientInfo.type == ClientInfo.ClientType.JAVA && clientInfo.version.compareTo(VersionUtil.parseVersion("1.0.0")) >= 0) { result.put("dom", serviceName); } else { result.put("dom", NamingUtils.getServiceName(serviceName)); } - + result.put("hosts", JacksonUtils.createEmptyArrayNode()); result.put("name", serviceName); result.put("cacheMillis", cacheMillis); @@ -576,57 +576,57 @@ public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent result.put("metadata", JacksonUtils.transferToJsonNode(service.getMetadata())); return result; } - + Map> ipMap = new HashMap<>(2); ipMap.put(Boolean.TRUE, new ArrayList<>()); ipMap.put(Boolean.FALSE, new ArrayList<>()); - + for (Instance ip : srvedIPs) { ipMap.get(ip.isHealthy()).add(ip); } - + if (isCheck) { result.put("reachProtectThreshold", false); } - + double threshold = service.getProtectThreshold(); - + if ((float) ipMap.get(Boolean.TRUE).size() / srvedIPs.size() <= threshold) { - + Loggers.SRV_LOG.warn("protect threshold reached, return all ips, service: {}", serviceName); if (isCheck) { result.put("reachProtectThreshold", true); } - + ipMap.get(Boolean.TRUE).addAll(ipMap.get(Boolean.FALSE)); ipMap.get(Boolean.FALSE).clear(); } - + if (isCheck) { result.put("protectThreshold", service.getProtectThreshold()); result.put("reachLocalSiteCallThreshold", false); - + return JacksonUtils.createEmptyJsonNode(); } - + ArrayNode hosts = JacksonUtils.createEmptyArrayNode(); - + for (Map.Entry> entry : ipMap.entrySet()) { List ips = entry.getValue(); - + if (healthyOnly && !entry.getKey()) { continue; } - + for (Instance instance : ips) { - + // remove disabled instance: if (!instance.isEnabled()) { continue; } - + ObjectNode ipObj = JacksonUtils.createEmptyJsonNode(); - + ipObj.put("ip", instance.getIp()); ipObj.put("port", instance.getPort()); // deprecated since nacos 1.0.0: @@ -644,13 +644,13 @@ public ObjectNode doSrvIpxt(String namespaceId, String serviceName, String agent } else { ipObj.put("serviceName", NamingUtils.getServiceName(instance.getServiceName())); } - + ipObj.put("ephemeral", instance.isEphemeral()); hosts.add(ipObj); - + } } - + result.replace("hosts", hosts); if (clientInfo.type == ClientInfo.ClientType.JAVA && clientInfo.version.compareTo(VersionUtil.parseVersion("1.0.0")) >= 0) { diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java b/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java index b1e83694538..b01482ab9ce 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java @@ -43,38 +43,38 @@ * @author jifengnan 2019-04-26 */ public class Cluster extends com.alibaba.nacos.api.naming.pojo.Cluster implements Cloneable { - + private static final String CLUSTER_NAME_SYNTAX = "[0-9a-zA-Z-]+"; - + /** * a addition for same site routing, can group multiple sites into a region, like Hangzhou, Shanghai, etc. */ private String sitegroup = StringUtils.EMPTY; - + private int defCkport = 80; - + private int defIpPort = -1; - + @JsonIgnore private HealthCheckTask checkTask; - + @JsonIgnore private Set persistentInstances = new HashSet<>(); - + @JsonIgnore private Set ephemeralInstances = new HashSet<>(); - + @JsonIgnore private Service service; - + @JsonIgnore private volatile boolean inited = false; - + private Map metadata = new ConcurrentHashMap<>(); - + public Cluster() { } - + /** * Create a cluster. * @@ -92,7 +92,7 @@ public Cluster(String clusterName, Service service) { this.service = service; validate(); } - + /** * Reason why method is not camel is that the old version has released, and the method name will be as the key * serialize and deserialize for Json. So ignore checkstyle. @@ -104,7 +104,7 @@ public int getDefIPPort() { // for compatibility with old entries return defIpPort == -1 ? defCkport : defIpPort; } - + @SuppressWarnings("checkstyle:abbreviationaswordinname") public void setDefIPPort(int defIpPort) { if (defIpPort == 0) { @@ -112,7 +112,7 @@ public void setDefIPPort(int defIpPort) { } this.defIpPort = defIpPort; } - + /** * Get all instances. * @@ -124,7 +124,7 @@ public List allIPs() { allInstances.addAll(ephemeralInstances); return allInstances; } - + /** * Get all ephemeral or consistence instances. * @@ -134,7 +134,7 @@ public List allIPs() { public List allIPs(boolean ephemeral) { return ephemeral ? new ArrayList<>(ephemeralInstances) : new ArrayList<>(persistentInstances); } - + /** * Init cluster. */ @@ -143,11 +143,11 @@ public void init() { return; } checkTask = new HealthCheckTask(this); - + HealthCheckReactor.scheduleCheck(checkTask); inited = true; } - + /** * Destroy cluster. */ @@ -156,16 +156,16 @@ public void destroy() { checkTask.setCancelled(true); } } - + @JsonIgnore public HealthCheckTask getHealthCheckTask() { return checkTask; } - + public Service getService() { return service; } - + /** * Replace the service for the current cluster. * @@ -181,7 +181,7 @@ public void setService(Service service) { } this.service = service; } - + /** * this method has been deprecated, the service name shouldn't be changed. * @@ -194,7 +194,7 @@ public void setService(Service service) { public void setServiceName(String serviceName) { super.setServiceName(serviceName); } - + /** * Get the service name of the current cluster. * @@ -211,7 +211,7 @@ public String getServiceName() { return super.getServiceName(); } } - + @Override public Cluster clone() throws CloneNotSupportedException { super.clone(); @@ -222,11 +222,11 @@ public Cluster clone() throws CloneNotSupportedException { cluster.metadata = new HashMap<>(metadata); return cluster; } - + public boolean isEmpty() { return ephemeralInstances.isEmpty() && persistentInstances.isEmpty(); } - + /** * Update instance list. * @@ -234,33 +234,33 @@ public boolean isEmpty() { * @param ephemeral whether these instances are ephemeral */ public void updateIps(List ips, boolean ephemeral) { - + Set toUpdateInstances = ephemeral ? ephemeralInstances : persistentInstances; - + HashMap oldIpMap = new HashMap<>(toUpdateInstances.size()); - + for (Instance ip : toUpdateInstances) { oldIpMap.put(ip.getDatumKey(), ip); } - + List 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(), @@ -268,85 +268,86 @@ public void updateIps(List ips, boolean ephemeral) { } } } - + List 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 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); - + if (ephemeral) { ephemeralInstances = toUpdateInstances; } else { persistentInstances = toUpdateInstances; } } - + private List updatedIps(Collection newInstance, Collection oldInstance) { - + List intersects = (List) CollectionUtils.intersection(newInstance, oldInstance); - Map ipAddressMap = new ConcurrentHashMap<>(intersects.size()); - + Map stringIpAddressMap = new ConcurrentHashMap<>(intersects.size()); + for (Instance instance : intersects) { - ipAddressMap.put(instance.getIp() + ":" + instance.getPort(), instance); + stringIpAddressMap.put(instance.getIp() + ":" + instance.getPort(), instance); } - + Map intersectMap = new ConcurrentHashMap<>(newInstance.size() + oldInstance.size()); Map instanceMap = new ConcurrentHashMap<>(newInstance.size()); Map instancesMap = new ConcurrentHashMap<>(newInstance.size()); - + for (Instance instance : oldInstance) { - if (ipAddressMap.containsKey(instance.getIp() + ":" + instance.getPort())) { + if (stringIpAddressMap.containsKey(instance.getIp() + ":" + instance.getPort())) { intersectMap.put(instance.toString(), 1); } } - + for (Instance instance : newInstance) { - if (ipAddressMap.containsKey(instance.getIp() + ":" + instance.getPort())) { - + if (stringIpAddressMap.containsKey(instance.getIp() + ":" + instance.getPort())) { + if (intersectMap.containsKey(instance.toString())) { intersectMap.put(instance.toString(), 2); } else { intersectMap.put(instance.toString(), 1); } } - + instancesMap.put(instance.toString(), instance); - + } - + for (Map.Entry entry : intersectMap.entrySet()) { String key = entry.getKey(); Integer value = entry.getValue(); - + if (value == 1) { if (instancesMap.containsKey(key)) { instanceMap.put(key, instancesMap.get(key)); } } } - + return new ArrayList<>(instanceMap.values()); } + private List subtract(Collection oldIp, Collection ips) { Map ipsMap = new HashMap<>(ips.size()); for (Instance instance : ips) { @@ -362,84 +363,84 @@ private List subtract(Collection oldIp, Collection } return instanceResult; } - + @Override public int hashCode() { return Objects.hash(getName()); } - + @Override public boolean equals(Object obj) { if (!(obj instanceof Cluster)) { return false; } - + return getName().equals(((Cluster) obj).getName()); } - + public int getDefCkport() { return defCkport; } - + public void setDefCkport(int defCkport) { this.defCkport = defCkport; } - + /** * Update cluster from other cluster. * * @param cluster new cluster */ public void update(Cluster cluster) { - + if (!getHealthChecker().equals(cluster.getHealthChecker())) { Loggers.SRV_LOG.info("[CLUSTER-UPDATE] {}:{}:, healthChecker: {} -> {}", getService().getName(), getName(), getHealthChecker().toString(), cluster.getHealthChecker().toString()); setHealthChecker(cluster.getHealthChecker()); } - + if (defCkport != cluster.getDefCkport()) { Loggers.SRV_LOG .info("[CLUSTER-UPDATE] {}:{}, defCkport: {} -> {}", getService().getName(), getName(), defCkport, cluster.getDefCkport()); defCkport = cluster.getDefCkport(); } - + if (defIpPort != cluster.getDefIPPort()) { Loggers.SRV_LOG .info("[CLUSTER-UPDATE] {}:{}, defIPPort: {} -> {}", getService().getName(), getName(), defIpPort, cluster.getDefIPPort()); defIpPort = cluster.getDefIPPort(); } - + if (!StringUtils.equals(sitegroup, cluster.getSitegroup())) { Loggers.SRV_LOG .info("[CLUSTER-UPDATE] {}:{}, sitegroup: {} -> {}", getService().getName(), getName(), sitegroup, cluster.getSitegroup()); sitegroup = cluster.getSitegroup(); } - + if (isUseIPPort4Check() != cluster.isUseIPPort4Check()) { Loggers.SRV_LOG.info("[CLUSTER-UPDATE] {}:{}, useIPPort4Check: {} -> {}", getService().getName(), getName(), isUseIPPort4Check(), cluster.isUseIPPort4Check()); setUseIPPort4Check(cluster.isUseIPPort4Check()); } - + metadata = cluster.getMetadata(); } - + public String getSitegroup() { return sitegroup; } - + public void setSitegroup(String sitegroup) { this.sitegroup = sitegroup; } - + public boolean contains(Instance ip) { return persistentInstances.contains(ip) || ephemeralInstances.contains(ip); } - + /** * validate the current cluster. * diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java index 3c15f57b935..2b98048af48 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceManager.java @@ -72,44 +72,44 @@ */ @Component public class ServiceManager implements RecordListener { - + /** * Map(namespace, Map(group::serviceName, Service)). */ private final Map> serviceMap = new ConcurrentHashMap<>(); - + private final LinkedBlockingDeque toBeUpdatedServicesQueue = new LinkedBlockingDeque<>(1024 * 1024); - + private final Synchronizer synchronizer = new ServiceStatusSynchronizer(); - + private final Lock lock = new ReentrantLock(); - + @Resource(name = "consistencyDelegate") private ConsistencyService consistencyService; - + private final SwitchDomain switchDomain; - + private final DistroMapper distroMapper; - + private final ServerMemberManager memberManager; - + private final PushService pushService; - + private final RaftPeerSet raftPeerSet; - + private int maxFinalizeCount = 3; - + private final Object putServiceLock = new Object(); - + @Value("${nacos.naming.empty-service.auto-clean:false}") private boolean emptyServiceAutoClean; - + @Value("${nacos.naming.empty-service.clean.initial-delay-ms:60000}") private int cleanEmptyServiceDelay; - + @Value("${nacos.naming.empty-service.clean.period-time-ms:20000}") private int cleanEmptyServicePeriod; - + public ServiceManager(SwitchDomain switchDomain, DistroMapper distroMapper, ServerMemberManager memberManager, PushService pushService, RaftPeerSet raftPeerSet) { this.switchDomain = switchDomain; @@ -118,32 +118,32 @@ public ServiceManager(SwitchDomain switchDomain, DistroMapper distroMapper, Serv this.pushService = pushService; this.raftPeerSet = raftPeerSet; } - + /** * Init service maneger. */ @PostConstruct public void init() { - + UtilsAndCommons.SERVICE_SYNCHRONIZATION_EXECUTOR.schedule(new ServiceReporter(), 60000, TimeUnit.MILLISECONDS); - + UtilsAndCommons.SERVICE_UPDATE_EXECUTOR.submit(new UpdatedServiceProcessor()); - + if (emptyServiceAutoClean) { - + Loggers.SRV_LOG.info("open empty service auto clean job, initialDelay : {} ms, period : {} ms", cleanEmptyServiceDelay, cleanEmptyServicePeriod); - + // delay 60s, period 20s; - + // This task is not recommended to be performed frequently in order to avoid // the possibility that the service cache information may just be deleted // and then created due to the heartbeat mechanism - + GlobalExecutor.scheduleServiceAutoClean(new EmptyServiceAutoClean(), cleanEmptyServiceDelay, cleanEmptyServicePeriod); } - + try { Loggers.SRV_LOG.info("listen for service meta change"); consistencyService.listen(KeyBuilder.SERVICE_META_KEY_PREFIX, this); @@ -151,11 +151,11 @@ public void init() { Loggers.SRV_LOG.error("listen for service meta change failed!"); } } - + public Map chooseServiceMap(String namespaceId) { return serviceMap.get(namespaceId); } - + /** * Add a service into queue to update. * @@ -177,17 +177,17 @@ public void addUpdatedServiceToQueue(String namespaceId, String serviceName, Str lock.unlock(); } } - + @Override public boolean interests(String key) { return KeyBuilder.matchServiceMetaKey(key) && !KeyBuilder.matchSwitchKey(key); } - + @Override public boolean matchUnlistenKey(String key) { return KeyBuilder.matchServiceMetaKey(key) && !KeyBuilder.matchSwitchKey(key); } - + @Override public void onChange(String key, Service service) throws Exception { try { @@ -195,15 +195,15 @@ public void onChange(String key, Service service) throws Exception { Loggers.SRV_LOG.warn("received empty push from raft, key: {}", key); return; } - + if (StringUtils.isBlank(service.getNamespaceId())) { service.setNamespaceId(Constants.DEFAULT_NAMESPACE_ID); } - + Loggers.RAFT.info("[RAFT-NOTIFIER] datum is changed, key: {}, value: {}", key, service); - + Service oldDom = getService(service.getNamespaceId(), service.getName()); - + if (oldDom != null) { oldDom.update(service); // re-listen to handle the situation when the underlying listener is removed: @@ -220,34 +220,34 @@ public void onChange(String key, Service service) throws Exception { Loggers.SRV_LOG.error("[NACOS-SERVICE] error while processing service update", e); } } - + @Override public void onDelete(String key) throws Exception { String namespace = KeyBuilder.getNamespace(key); String name = KeyBuilder.getServiceName(key); Service service = chooseServiceMap(namespace).get(name); Loggers.RAFT.info("[RAFT-NOTIFIER] datum is deleted, key: {}", key); - + if (service != null) { service.destroy(); consistencyService.remove(KeyBuilder.buildInstanceListKey(namespace, name, true)); - + consistencyService.remove(KeyBuilder.buildInstanceListKey(namespace, name, false)); - + consistencyService.unListen(KeyBuilder.buildServiceMetaKey(namespace, name), service); Loggers.SRV_LOG.info("[DEAD-SERVICE] {}", service.toJson()); } - + chooseServiceMap(namespace).remove(name); } - + private class UpdatedServiceProcessor implements Runnable { - + //get changed service from other server asynchronously @Override public void run() { ServiceKey serviceKey = null; - + try { while (true) { try { @@ -255,7 +255,7 @@ public void run() { } catch (Exception e) { Loggers.EVT_LOG.error("[UPDATE-DOMAIN] Exception while taking item from LinkedBlockingDeque."); } - + if (serviceKey == null) { continue; } @@ -266,21 +266,21 @@ public void run() { } } } - + private class ServiceUpdater implements Runnable { - + String namespaceId; - + String serviceName; - + String serverIP; - + public ServiceUpdater(ServiceKey serviceKey) { this.namespaceId = serviceKey.getNamespaceId(); this.serviceName = serviceKey.getServiceName(); this.serverIP = serviceKey.getServerIP(); } - + @Override public void run() { try { @@ -292,11 +292,11 @@ public void run() { } } } - + public RaftPeer getMySelfClusterState() { return raftPeerSet.local(); } - + /** * Update health status of instance in service. * @@ -307,27 +307,27 @@ public RaftPeer getMySelfClusterState() { public void updatedHealthStatus(String namespaceId, String serviceName, String serverIP) { Message msg = synchronizer.get(serverIP, UtilsAndCommons.assembleFullServiceName(namespaceId, serviceName)); JsonNode serviceJson = JacksonUtils.toObj(msg.getData()); - + ArrayNode ipList = (ArrayNode) serviceJson.get("ips"); Map ipsMap = new HashMap<>(ipList.size()); for (int i = 0; i < ipList.size(); i++) { - + String ip = ipList.get(i).asText(); String[] strings = ip.split("_"); ipsMap.put(strings[0], strings[1]); } - + Service service = getService(namespaceId, serviceName); - + if (service == null) { return; } - + boolean changed = false; - + List instances = service.allIPs(); for (Instance instance : instances) { - + boolean valid = Boolean.parseBoolean(ipsMap.get(instance.toIpAddr())); if (valid != instance.isHealthy()) { changed = true; @@ -337,7 +337,7 @@ public void updatedHealthStatus(String namespaceId, String serviceName, String s instance.getClusterName()); } } - + if (changed) { pushService.serviceChanged(service); if (Loggers.EVT_LOG.isDebugEnabled()) { @@ -351,33 +351,33 @@ public void updatedHealthStatus(String namespaceId, String serviceName, String s service.getName(), stringBuilder.toString()); } } - + } - + public Set getAllServiceNames(String namespaceId) { return serviceMap.get(namespaceId).keySet(); } - + public Map> getAllServiceNames() { - + Map> namesMap = new HashMap<>(16); for (String namespaceId : serviceMap.keySet()) { namesMap.put(namespaceId, serviceMap.get(namespaceId).keySet()); } return namesMap; } - + public Set getAllNamespaces() { return serviceMap.keySet(); } - + public List getAllServiceNameList(String namespaceId) { if (chooseServiceMap(namespaceId) == null) { return new ArrayList<>(); } return new ArrayList<>(chooseServiceMap(namespaceId).keySet()); } - + public Map> getResponsibleServices() { Map> result = new HashMap<>(16); for (String namespaceId : serviceMap.keySet()) { @@ -391,7 +391,7 @@ public Map> getResponsibleServices() { } return result; } - + public int getResponsibleServiceCount() { int serviceCount = 0; for (String namespaceId : serviceMap.keySet()) { @@ -403,7 +403,7 @@ public int getResponsibleServiceCount() { } return serviceCount; } - + public int getResponsibleInstanceCount() { Map> responsibleServices = getResponsibleServices(); int count = 0; @@ -412,10 +412,10 @@ public int getResponsibleInstanceCount() { count += service.allIPs().size(); } } - + return count; } - + /** * Fast remove service. * @@ -426,23 +426,23 @@ public int getResponsibleInstanceCount() { * @throws Exception exception */ public void easyRemoveService(String namespaceId, String serviceName) throws Exception { - + Service service = getService(namespaceId, serviceName); if (service == null) { throw new IllegalArgumentException("specified service not exist, serviceName : " + serviceName); } - + consistencyService.remove(KeyBuilder.buildServiceMetaKey(namespaceId, serviceName)); } - + public void addOrReplaceService(Service service) throws NacosException { consistencyService.put(KeyBuilder.buildServiceMetaKey(service.getNamespaceId(), service.getName()), service); } - + public void createEmptyService(String namespaceId, String serviceName, boolean local) throws NacosException { createServiceIfAbsent(namespaceId, serviceName, local, null); } - + /** * Create service if not exist. * @@ -456,7 +456,7 @@ public void createServiceIfAbsent(String namespaceId, String serviceName, boolea 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); @@ -470,14 +470,14 @@ public void createServiceIfAbsent(String namespaceId, String serviceName, boolea service.getClusterMap().put(cluster.getName(), cluster); } service.validate(); - + putServiceAndInit(service); if (!local) { addOrReplaceService(service); } } } - + /** * Register an instance to a service in AP mode. * @@ -489,19 +489,19 @@ public void createServiceIfAbsent(String namespaceId, String serviceName, boolea * @throws Exception any error occurred in the process */ public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException { - + createEmptyService(namespaceId, serviceName, instance.isEphemeral()); - + Service service = getService(namespaceId, serviceName); - + if (service == null) { throw new NacosException(NacosException.INVALID_PARAM, "service not found, namespace: " + namespaceId + ", service: " + serviceName); } - + addInstance(namespaceId, serviceName, instance.isEphemeral(), instance); } - + /** * Update instance to service. * @@ -511,21 +511,21 @@ public void registerInstance(String namespaceId, String serviceName, Instance in * @throws NacosException nacos exception */ public void updateInstance(String namespaceId, String serviceName, Instance instance) throws NacosException { - + Service service = getService(namespaceId, serviceName); - + if (service == null) { throw new NacosException(NacosException.INVALID_PARAM, "service not found, namespace: " + namespaceId + ", service: " + serviceName); } - + if (!service.allIPs().contains(instance)) { throw new NacosException(NacosException.INVALID_PARAM, "instance not exist: " + instance); } - + addInstance(namespaceId, serviceName, instance.isEphemeral(), instance); } - + /** * Add instance to service. * @@ -537,21 +537,21 @@ public void updateInstance(String namespaceId, String serviceName, Instance inst */ public void addInstance(String namespaceId, String serviceName, boolean ephemeral, Instance... ips) throws NacosException { - + String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral); - + Service service = getService(namespaceId, serviceName); - + synchronized (service) { List instanceList = addIpAddresses(service, ephemeral, ips); - + Instances instances = new Instances(); instances.setInstanceList(instanceList); - + consistencyService.put(key, instances); } } - + /** * Remove instance from service. * @@ -564,48 +564,48 @@ public void addInstance(String namespaceId, String serviceName, boolean ephemera public void removeInstance(String namespaceId, String serviceName, boolean ephemeral, Instance... ips) throws NacosException { Service service = getService(namespaceId, serviceName); - + synchronized (service) { removeInstance(namespaceId, serviceName, ephemeral, service, ips); } } - + private void removeInstance(String namespaceId, String serviceName, boolean ephemeral, Service service, Instance... ips) throws NacosException { - + String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral); - + List instanceList = substractIpAddresses(service, ephemeral, ips); - + Instances instances = new Instances(); instances.setInstanceList(instanceList); - + consistencyService.put(key, instances); } - + public Instance getInstance(String namespaceId, String serviceName, String cluster, String ip, int port) { Service service = getService(namespaceId, serviceName); if (service == null) { return null; } - + List clusters = new ArrayList<>(); clusters.add(cluster); - + List ips = service.allIPs(clusters); if (ips == null || ips.isEmpty()) { return null; } - + for (Instance instance : ips) { if (instance.getIp().equals(ip) && instance.getPort() == port) { return instance; } } - + return null; } - + /** * Compare and get new instance list. * @@ -618,26 +618,26 @@ public Instance getInstance(String namespaceId, String serviceName, String clust */ public List updateIpAddresses(Service service, String action, boolean ephemeral, Instance... ips) throws NacosException { - + Datum datum = consistencyService .get(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), ephemeral)); - + List currentIPs = service.allIPs(ephemeral); Map currentInstances = new HashMap<>(currentIPs.size()); Set currentInstanceIds = Sets.newHashSet(); - + for (Instance instance : currentIPs) { currentInstances.put(instance.toIpAddr(), instance); currentInstanceIds.add(instance.getInstanceId()); } - + Map instanceMap; if (datum != null) { 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); @@ -647,36 +647,36 @@ public List updateIpAddresses(Service service, String action, boolean .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.remove(instance.getDatumKey()); } 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()); } - + private List substractIpAddresses(Service service, boolean ephemeral, Instance... ips) throws NacosException { return updateIpAddresses(service, UtilsAndCommons.UPDATE_INSTANCE_ACTION_REMOVE, ephemeral, ips); } - + private List addIpAddresses(Service service, boolean ephemeral, Instance... ips) throws NacosException { return updateIpAddresses(service, UtilsAndCommons.UPDATE_INSTANCE_ACTION_ADD, ephemeral, ips); } - + private Map setValid(List oldInstances, Map map) { - + Map instanceMap = new HashMap<>(oldInstances.size()); for (Instance instance : oldInstances) { Instance instance1 = map.get(instance.toIpAddr()); @@ -688,18 +688,18 @@ private Map setValid(List oldInstances, Map searchServices(String namespaceId, String regex) { result.add(service); } } - + return result; } - + public int getServiceCount() { int serviceCount = 0; for (String namespaceId : serviceMap.keySet()) { @@ -753,7 +753,7 @@ public int getServiceCount() { } return serviceCount; } - + public int getInstanceCount() { int total = 0; for (String namespaceId : serviceMap.keySet()) { @@ -763,20 +763,20 @@ public int getInstanceCount() { } return total; } - + public Map getServiceMap(String namespaceId) { return serviceMap.get(namespaceId); } - + public int getPagedService(String namespaceId, int startPage, int pageSize, String param, String containedInstance, List serviceList, boolean hasIpCount) { - + List matchList; - + if (chooseServiceMap(namespaceId) == null) { return 0; } - + if (StringUtils.isNotBlank(param)) { StringJoiner regex = new StringJoiner(Constants.SERVICE_INFO_SPLITER); for (String s : param.split(Constants.SERVICE_INFO_SPLITER)) { @@ -787,14 +787,14 @@ public int getPagedService(String namespaceId, int startPage, int pageSize, Stri } else { matchList = new ArrayList<>(chooseServiceMap(namespaceId).values()); } - + if (!CollectionUtils.isEmpty(matchList) && hasIpCount) { matchList = matchList.stream().filter(s -> !CollectionUtils.isEmpty(s.allIPs())) .collect(Collectors.toList()); } - + if (StringUtils.isNotBlank(containedInstance)) { - + boolean contained; for (int i = 0; i < matchList.size(); i++) { Service service = matchList.get(i); @@ -819,41 +819,41 @@ public int getPagedService(String namespaceId, int startPage, int pageSize, Stri } } } - + if (pageSize >= matchList.size()) { serviceList.addAll(matchList); return matchList.size(); } - + for (int i = 0; i < matchList.size(); i++) { if (i < startPage * pageSize) { continue; } - + serviceList.add(matchList.get(i)); - + if (serviceList.size() >= pageSize) { break; } } - + return matchList.size(); } - + public static class ServiceChecksum { - + public String namespaceId; - + public Map serviceName2Checksum = new HashMap(); - + public ServiceChecksum() { this.namespaceId = Constants.DEFAULT_NAMESPACE_ID; } - + public ServiceChecksum(String namespaceId) { this.namespaceId = namespaceId; } - + /** * Add service checksum. * @@ -869,16 +869,16 @@ public void addItem(String serviceName, String checksum) { serviceName2Checksum.put(serviceName, checksum); } } - + private class EmptyServiceAutoClean implements Runnable { - + @Override public void run() { - + // Parallel flow opening threshold - + int parallelSize = 100; - + serviceMap.forEach((namespace, stringServiceMap) -> { Stream> stream = null; if (stringServiceMap.size() > parallelSize) { @@ -891,11 +891,11 @@ public void run() { return distroMapper.responsible(serviceName); }).forEach(entry -> stringServiceMap.computeIfPresent(entry.getKey(), (serviceName, service) -> { if (service.isEmpty()) { - + // To avoid violent Service removal, the number of times the Service // experiences Empty is determined by finalizeCnt, and if the specified // value is reached, it is removed - + if (service.getFinalizeCount() > maxFinalizeCount) { Loggers.SRV_LOG.warn("namespace : {}, [{}] services are automatically cleaned", namespace, serviceName); @@ -906,9 +906,9 @@ public void run() { + "error : {}", namespace, serviceName, e); } } - + service.setFinalizeCount(service.getFinalizeCount() + 1); - + Loggers.SRV_LOG .debug("namespace : {}, [{}] The number of times the current service experiences " + "an empty instance is : {}", namespace, serviceName, @@ -921,50 +921,50 @@ public void run() { }); } } - + private class ServiceReporter implements Runnable { - + @Override public void run() { try { - + Map> allServiceNames = getAllServiceNames(); - + if (allServiceNames.size() <= 0) { //ignore return; } - + for (String namespaceId : allServiceNames.keySet()) { - + ServiceChecksum checksum = new ServiceChecksum(namespaceId); - + for (String serviceName : allServiceNames.get(namespaceId)) { if (!distroMapper.responsible(serviceName)) { continue; } - + Service service = getService(namespaceId, serviceName); - + if (service == null || service.isEmpty()) { continue; } - + service.recalculateChecksum(); - + checksum.addItem(serviceName, service.getChecksum()); } - + Message msg = new Message(); - + msg.setData(JacksonUtils.toJson(checksum)); - + Collection sameSiteServers = memberManager.allMembers(); - + if (sameSiteServers == null || sameSiteServers.size() <= 0) { return; } - + for (Member server : sameSiteServers) { if (server.getAddress().equals(NetUtils.localServer())) { continue; @@ -981,40 +981,40 @@ public void run() { } } } - + private static class ServiceKey { - + private String namespaceId; - + private String serviceName; - + private String serverIP; - + private String checksum; - + public String getChecksum() { return checksum; } - + public String getServerIP() { return serverIP; } - + public String getServiceName() { return serviceName; } - + public String getNamespaceId() { return namespaceId; } - + public ServiceKey(String namespaceId, String serviceName, String serverIP, String checksum) { this.namespaceId = namespaceId; this.serviceName = serviceName; this.serverIP = serverIP; this.checksum = checksum; } - + @Override public String toString() { return JacksonUtils.toJson(this); From e21ba6241d637ead918385522859214dd454077a Mon Sep 17 00:00:00 2001 From: pengzhengfa <13656694002@163.com> Date: Thu, 18 Jun 2020 15:15:48 +0800 Subject: [PATCH 5/6] Method name optimization --- .../alibaba/nacos/naming/core/Cluster.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java b/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java index b01482ab9ce..ed876582195 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/Cluster.java @@ -311,8 +311,8 @@ private List updatedIps(Collection newInstance, Collection intersectMap = new ConcurrentHashMap<>(newInstance.size() + oldInstance.size()); - Map instanceMap = new ConcurrentHashMap<>(newInstance.size()); - Map instancesMap = new ConcurrentHashMap<>(newInstance.size()); + Map updatedInstancesMap = new ConcurrentHashMap<>(newInstance.size()); + Map newInstancesMap = new ConcurrentHashMap<>(newInstance.size()); for (Instance instance : oldInstance) { if (stringIpAddressMap.containsKey(instance.getIp() + ":" + instance.getPort())) { @@ -329,8 +329,8 @@ private List updatedIps(Collection newInstance, Collection updatedIps(Collection newInstance, Collection(instanceMap.values()); + return new ArrayList<>(updatedInstancesMap.values()); } - + private List subtract(Collection oldIp, Collection ips) { Map ipsMap = new HashMap<>(ips.size()); for (Instance instance : ips) { ipsMap.put(instance.getIp() + ":" + instance.getPort(), instance); } - + List instanceResult = new ArrayList<>(); - + for (Instance instance : oldIp) { if (!ipsMap.containsKey(instance.getIp() + ":" + instance.getPort())) { instanceResult.add(instance); From 49b579f4cfbc0a4b43de7f1149159aea4b27ea69 Mon Sep 17 00:00:00 2001 From: pengzhengfa <13656694002@163.com> Date: Thu, 18 Jun 2020 16:12:10 +0800 Subject: [PATCH 6/6] Optimize the naming of persistence layer --- .../consistency/persistent/raft/RaftConsistencyServiceImpl.java | 2 +- .../nacos/naming/consistency/persistent/raft/RaftCore.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java index 89ca241b4f1..c50241b710e 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftConsistencyServiceImpl.java @@ -89,7 +89,7 @@ public void listen(String key, RecordListener listener) throws NacosException { @Override public void unListen(String key, RecordListener listener) throws NacosException { - raftCore.unlisten(key, listener); + raftCore.unListen(key, listener); } @Override diff --git a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java index 7ec7f8fa9b9..6a5d56e0d35 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java @@ -904,7 +904,7 @@ public void listen(String key, RecordListener listener) { * @param key key * @param listener listener */ - public void unlisten(String key, RecordListener listener) { + public void unListen(String key, RecordListener listener) { if (!listeners.containsKey(key)) { return;