From 164ed33ada04d713219e9c1af1f6505333341997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E7=BF=8A=20SionYang?= <263976490@qq.com> Date: Wed, 11 Nov 2020 19:50:14 +0800 Subject: [PATCH] Feature support grpc core (#4204) * NacosNamingMetadataManager --> NamingMetadataManager * Try to add ServiceMetadata consistency * add catalog api support new data * Change version to 2.0.0-SNAPSHOT --- address/pom.xml | 2 +- api/pom.xml | 2 +- auth/pom.xml | 2 +- client/pom.xml | 2 +- cmdb/pom.xml | 2 +- common/pom.xml | 2 +- config/pom.xml | 2 +- consistency/pom.xml | 2 +- console/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- example/pom.xml | 2 +- istio/pom.xml | 2 +- naming/pom.xml | 2 +- .../naming/controllers/CatalogController.java | 161 ++----------- .../nacos/naming/core/CatalogService.java | 84 +++++++ .../naming/core/CatalogServiceV1Impl.java | 194 ++++++++++++++++ .../naming/core/CatalogServiceV2Impl.java | 211 ++++++++++++++++++ .../naming/core/v2/index/ServiceStorage.java | 21 +- .../core/v2/metadata/MetadataOperation.java | 65 ++++++ ...anager.java => NamingMetadataManager.java} | 4 +- .../NamingMetadataOperateService.java | 93 ++++++++ .../core/v2/metadata/ServiceMetadata.java | 32 ++- .../v2/metadata/ServiceMetadataProcessor.java | 102 +++++++++ .../EphemeralClientOperationServiceImpl.java | 1 + .../heartbeat/ClientBeatCheckTaskV2.java | 6 +- .../heartbeat/ExpiredInstanceChecker.java | 4 +- .../InstanceEnableBeatCheckInterceptor.java | 4 +- .../ServiceEnableBeatCheckInterceptor.java | 4 +- .../heartbeat/UnhealthyInstanceChecker.java | 4 +- .../alibaba/nacos/naming/utils/Constants.java | 2 +- .../controllers/CatalogControllerTest.java | 2 +- .../heartbeat/ClientBeatCheckTaskV2Test.java | 8 +- .../HealthCheckTaskInterceptWrapperTest.java | 8 +- pom.xml | 4 +- sys/pom.xml | 2 +- test/pom.xml | 2 +- 37 files changed, 856 insertions(+), 190 deletions(-) create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/core/CatalogService.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/core/CatalogServiceV1Impl.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/core/CatalogServiceV2Impl.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/MetadataOperation.java rename naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/{NacosNamingMetadataManager.java => NamingMetadataManager.java} (98%) create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataOperateService.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataProcessor.java diff --git a/address/pom.xml b/address/pom.xml index 5db51447c..475582f82 100644 --- a/address/pom.xml +++ b/address/pom.xml @@ -19,7 +19,7 @@ nacos-all com.alibaba.nacos - 2.0.0-ALPHA + 2.0.0-SNAPSHOT 4.0.0 diff --git a/api/pom.xml b/api/pom.xml index 4e1143c8b..c2cc72f73 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -19,7 +19,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT 4.0.0 diff --git a/auth/pom.xml b/auth/pom.xml index d350fe492..572600f50 100644 --- a/auth/pom.xml +++ b/auth/pom.xml @@ -21,7 +21,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/client/pom.xml b/client/pom.xml index 3340b3ab4..af7216f89 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -19,7 +19,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT ../pom.xml diff --git a/cmdb/pom.xml b/cmdb/pom.xml index d223a2e15..5ad21d8cb 100644 --- a/cmdb/pom.xml +++ b/cmdb/pom.xml @@ -21,7 +21,7 @@ nacos-all com.alibaba.nacos - 2.0.0-ALPHA + 2.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/common/pom.xml b/common/pom.xml index af54a0dd9..9ae93f830 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -21,7 +21,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/config/pom.xml b/config/pom.xml index 990aace4e..4a614671f 100644 --- a/config/pom.xml +++ b/config/pom.xml @@ -20,7 +20,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT 4.0.0 diff --git a/consistency/pom.xml b/consistency/pom.xml index c713df2b6..eb4d2bb99 100644 --- a/consistency/pom.xml +++ b/consistency/pom.xml @@ -85,7 +85,7 @@ com.alibaba.nacos nacos-all ../pom.xml - 2.0.0-ALPHA + 2.0.0-SNAPSHOT diff --git a/console/pom.xml b/console/pom.xml index 11d98a6a2..f472b4232 100644 --- a/console/pom.xml +++ b/console/pom.xml @@ -21,7 +21,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT nacos-console jar diff --git a/core/pom.xml b/core/pom.xml index 49c468b03..3c63a371f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT ../pom.xml diff --git a/distribution/pom.xml b/distribution/pom.xml index a7fa42583..ea876cc4a 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -21,7 +21,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT ../pom.xml diff --git a/example/pom.xml b/example/pom.xml index be732f90c..8a4b2337d 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -21,7 +21,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT ../pom.xml diff --git a/istio/pom.xml b/istio/pom.xml index bbd3c7d12..c8937f4c8 100644 --- a/istio/pom.xml +++ b/istio/pom.xml @@ -19,7 +19,7 @@ nacos-all com.alibaba.nacos - 2.0.0-ALPHA + 2.0.0-SNAPSHOT 4.0.0 diff --git a/naming/pom.xml b/naming/pom.xml index 426f83205..d3312dd0b 100644 --- a/naming/pom.xml +++ b/naming/pom.xml @@ -21,7 +21,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT ../pom.xml diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/CatalogController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/CatalogController.java index ce0992e8f..c9ce30fff 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/CatalogController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/CatalogController.java @@ -19,26 +19,21 @@ package com.alibaba.nacos.naming.controllers; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.CommonParams; -import com.alibaba.nacos.api.naming.pojo.Cluster; +import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.utils.NamingUtils; import com.alibaba.nacos.auth.annotation.Secured; import com.alibaba.nacos.auth.common.ActionTypes; import com.alibaba.nacos.common.utils.JacksonUtils; import com.alibaba.nacos.core.utils.WebUtils; -import com.alibaba.nacos.naming.core.Instance; +import com.alibaba.nacos.naming.core.CatalogServiceV1Impl; +import com.alibaba.nacos.naming.core.CatalogServiceV2Impl; import com.alibaba.nacos.naming.core.Service; import com.alibaba.nacos.naming.core.ServiceManager; import com.alibaba.nacos.naming.healthcheck.HealthCheckTask; import com.alibaba.nacos.naming.misc.UtilsAndCommons; -import com.alibaba.nacos.naming.pojo.ClusterInfo; -import com.alibaba.nacos.naming.pojo.IpAddressInfo; -import com.alibaba.nacos.naming.pojo.ServiceDetailInfo; -import com.alibaba.nacos.naming.pojo.ServiceView; import com.alibaba.nacos.naming.web.NamingResourceParser; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; - -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; @@ -47,10 +42,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -66,6 +57,12 @@ public class CatalogController { @Autowired protected ServiceManager serviceManager; + @Autowired + private CatalogServiceV1Impl catalogServiceV1; + + @Autowired + private CatalogServiceV2Impl catalogServiceV2; + /** * Get service detail. * @@ -76,41 +73,11 @@ public class CatalogController { */ @Secured(parser = NamingResourceParser.class, action = ActionTypes.READ) @GetMapping("/service") - public ObjectNode serviceDetail(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId, + public Object serviceDetail(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId, String serviceName) throws NacosException { - - Service detailedService = serviceManager.getService(namespaceId, serviceName); - - if (detailedService == null) { - throw new NacosException(NacosException.NOT_FOUND, "service " + serviceName + " is not found!"); - } - ObjectNode serviceObject = JacksonUtils.createEmptyJsonNode(); - serviceObject.put("name", NamingUtils.getServiceName(serviceName)); - serviceObject.put("protectThreshold", detailedService.getProtectThreshold()); - serviceObject.put("groupName", NamingUtils.getGroupName(serviceName)); - serviceObject.replace("selector", JacksonUtils.transferToJsonNode(detailedService.getSelector())); - serviceObject.replace("metadata", JacksonUtils.transferToJsonNode(detailedService.getMetadata())); - - ObjectNode detailView = JacksonUtils.createEmptyJsonNode(); - detailView.replace("service", serviceObject); - - List clusters = new ArrayList<>(); - - for (com.alibaba.nacos.naming.core.Cluster cluster : detailedService.getClusterMap().values()) { - Cluster clusterView = new Cluster(); - clusterView.setName(cluster.getName()); - clusterView.setHealthChecker(cluster.getHealthChecker()); - clusterView.setMetadata(cluster.getMetadata()); - clusterView.setUseIPPort4Check(cluster.isUseIPPort4Check()); - clusterView.setDefaultPort(cluster.getDefaultPort()); - clusterView.setDefaultCheckPort(cluster.getDefaultCheckPort()); - clusterView.setServiceName(cluster.getService().getName()); - clusters.add(clusterView); - } - - detailView.replace("clusters", JacksonUtils.transferToJsonNode(clusters)); - - return detailView; + String serviceNameWithoutGroup = NamingUtils.getServiceName(serviceName); + String groupName = NamingUtils.getGroupName(serviceName); + return catalogServiceV2.getServiceDetail(namespaceId, groupName, serviceNameWithoutGroup); } /** @@ -129,18 +96,10 @@ public class CatalogController { public ObjectNode instanceList(@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId, @RequestParam String serviceName, @RequestParam String clusterName, @RequestParam(name = "pageNo") int page, @RequestParam int pageSize) throws NacosException { - - Service service = serviceManager.getService(namespaceId, serviceName); - if (service == null) { - throw new NacosException(NacosException.NOT_FOUND, "serivce " + serviceName + " is not found!"); - } - - if (!service.getClusterMap().containsKey(clusterName)) { - throw new NacosException(NacosException.NOT_FOUND, "cluster " + clusterName + " is not found!"); - } - - List instances = service.getClusterMap().get(clusterName).allIPs(); - + String serviceNameWithoutGroup = NamingUtils.getServiceName(serviceName); + String groupName = NamingUtils.getGroupName(serviceName); + List instances = catalogServiceV2 + .listInstances(namespaceId, groupName, serviceNameWithoutGroup, clusterName); int start = (page - 1) * pageSize; int end = page * pageSize; @@ -184,58 +143,13 @@ public class CatalogController { @RequestParam(name = "serviceNameParam", defaultValue = StringUtils.EMPTY) String serviceName, @RequestParam(name = "groupNameParam", defaultValue = StringUtils.EMPTY) String groupName, @RequestParam(name = "instance", defaultValue = StringUtils.EMPTY) String containedInstance, - @RequestParam(required = false) boolean hasIpCount) { - - String param = StringUtils.isBlank(serviceName) && StringUtils.isBlank(groupName) ? StringUtils.EMPTY - : NamingUtils.getGroupedName(serviceName, groupName); + @RequestParam(required = false) boolean hasIpCount) throws NacosException { if (withInstances) { - List serviceDetailInfoList = new ArrayList<>(); - - List services = new ArrayList<>(8); - serviceManager.getPagedService(namespaceId, pageNo, pageSize, param, StringUtils.EMPTY, services, false); - - for (Service service : services) { - ServiceDetailInfo serviceDetailInfo = new ServiceDetailInfo(); - serviceDetailInfo.setServiceName(NamingUtils.getServiceName(service.getName())); - serviceDetailInfo.setGroupName(NamingUtils.getGroupName(service.getName())); - serviceDetailInfo.setMetadata(service.getMetadata()); - - Map clusterInfoMap = getStringClusterInfoMap(service); - serviceDetailInfo.setClusterMap(clusterInfoMap); - - serviceDetailInfoList.add(serviceDetailInfo); - } - - return serviceDetailInfoList; + return catalogServiceV2.pageListServiceDetail(namespaceId, groupName, serviceName, pageNo, pageSize); } - - ObjectNode result = JacksonUtils.createEmptyJsonNode(); - - List services = new ArrayList<>(); - final int total = serviceManager.getPagedService(namespaceId, pageNo - 1, pageSize, param, containedInstance, services, hasIpCount); - if (CollectionUtils.isEmpty(services)) { - result.replace("serviceList", JacksonUtils.transferToJsonNode(Collections.emptyList())); - result.put("count", 0); - return result; - } - - List serviceViews = new LinkedList<>(); - for (Service service : services) { - ServiceView serviceView = new ServiceView(); - serviceView.setName(NamingUtils.getServiceName(service.getName())); - serviceView.setGroupName(NamingUtils.getGroupName(service.getName())); - serviceView.setClusterCount(service.getClusterMap().size()); - serviceView.setIpCount(service.allIPs().size()); - serviceView.setHealthyInstanceCount(service.healthyInstanceCount()); - serviceView.setTriggerFlag(service.triggerFlag() ? "true" : "false"); - serviceViews.add(serviceView); - } - - result.replace("serviceList", JacksonUtils.transferToJsonNode(serviceViews)); - result.put("count", total); - - return result; + return catalogServiceV2 + .pageListService(namespaceId, groupName, serviceName, pageNo, pageSize, containedInstance, hasIpCount); } /** @@ -273,37 +187,4 @@ public class CatalogController { result.replace("clusters", clusters); return result; } - - private Map getStringClusterInfoMap(Service service) { - Map clusterInfoMap = new HashMap<>(8); - - service.getClusterMap().forEach((clusterName, cluster) -> { - - ClusterInfo clusterInfo = new ClusterInfo(); - List ipAddressInfos = getIpAddressInfos(cluster.allIPs()); - clusterInfo.setHosts(ipAddressInfos); - clusterInfoMap.put(clusterName, clusterInfo); - - }); - return clusterInfoMap; - } - - private List getIpAddressInfos(List instances) { - List ipAddressInfos = new ArrayList<>(); - - instances.forEach((ipAddress) -> { - - IpAddressInfo ipAddressInfo = new IpAddressInfo(); - ipAddressInfo.setIp(ipAddress.getIp()); - ipAddressInfo.setPort(ipAddress.getPort()); - ipAddressInfo.setMetadata(ipAddress.getMetadata()); - ipAddressInfo.setValid(ipAddress.isHealthy()); - ipAddressInfo.setWeight(ipAddress.getWeight()); - ipAddressInfo.setEnabled(ipAddress.isEnabled()); - ipAddressInfos.add(ipAddressInfo); - - }); - return ipAddressInfos; - } - } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/CatalogService.java b/naming/src/main/java/com/alibaba/nacos/naming/core/CatalogService.java new file mode 100644 index 000000000..35d332423 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/CatalogService.java @@ -0,0 +1,84 @@ +/* + * Copyright 1999-2020 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.naming.core; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.pojo.Instance; + +import java.util.List; + +/** + * Catalog service. + * + * @author xiweng.yy + */ +public interface CatalogService { + + /** + * Get service detail information. + * + * @param namespaceId namespace id of service + * @param groupName group name of service + * @param serviceName service name + * @return detail information of service + * @throws NacosException exception in query + */ + Object getServiceDetail(String namespaceId, String groupName, String serviceName) throws NacosException; + + /** + * List all instances of specified services. + * + * @param namespaceId namespace id of service + * @param groupName group name of service + * @param serviceName service name + * @param clusterName cluster name of instances + * @return instances list + * @throws NacosException exception in query + */ + List listInstances(String namespaceId, String groupName, String serviceName, String clusterName) + throws NacosException; + + /** + * List service by page. + * + * @param namespaceId namespace id of service + * @param groupName group name of service + * @param serviceName service name + * @param pageNo page number + * @param pageSize page size + * @param instancePattern contained instances pattern + * @param ignoreEmptyService whether ignore empty service + * @return service list + * @throws NacosException exception in query + */ + Object pageListService(String namespaceId, String groupName, String serviceName, int pageNo, int pageSize, + String instancePattern, boolean ignoreEmptyService) throws NacosException; + + /** + * List service with cluster and instances by page. + * + * @param namespaceId namespace id of service + * @param groupName group name of service + * @param serviceName service name + * @param pageNo page number + * @param pageSize page size + * @return service list + * @throws NacosException exception in query + */ + Object pageListServiceDetail(String namespaceId, String groupName, String serviceName, int pageNo, int pageSize) + throws NacosException; +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/CatalogServiceV1Impl.java b/naming/src/main/java/com/alibaba/nacos/naming/core/CatalogServiceV1Impl.java new file mode 100644 index 000000000..23539f98d --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/CatalogServiceV1Impl.java @@ -0,0 +1,194 @@ +/* + * Copyright 1999-2020 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.naming.core; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.utils.NamingUtils; +import com.alibaba.nacos.common.utils.JacksonUtils; +import com.alibaba.nacos.naming.pojo.ClusterInfo; +import com.alibaba.nacos.naming.pojo.IpAddressInfo; +import com.alibaba.nacos.naming.pojo.ServiceDetailInfo; +import com.alibaba.nacos.naming.pojo.ServiceView; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * Catalog service for v1.x . + * + * @author xiweng.yy + */ +@Component() +public class CatalogServiceV1Impl implements CatalogService { + + private final ServiceManager serviceManager; + + public CatalogServiceV1Impl(ServiceManager serviceManager) { + this.serviceManager = serviceManager; + } + + @Override + public Object getServiceDetail(String namespaceId, String groupName, String serviceName) throws NacosException { + Service detailedService = serviceManager.getService(namespaceId, NamingUtils.getGroupedName(serviceName, groupName)); + + if (detailedService == null) { + throw new NacosException(NacosException.NOT_FOUND, + String.format("service %s@@%s is not found!", groupName, serviceName)); + } + ObjectNode serviceObject = JacksonUtils.createEmptyJsonNode(); + serviceObject.put("name", serviceName); + serviceObject.put("protectThreshold", detailedService.getProtectThreshold()); + serviceObject.put("groupName", groupName); + serviceObject.replace("selector", JacksonUtils.transferToJsonNode(detailedService.getSelector())); + serviceObject.replace("metadata", JacksonUtils.transferToJsonNode(detailedService.getMetadata())); + + ObjectNode detailView = JacksonUtils.createEmptyJsonNode(); + detailView.replace("service", serviceObject); + + List clusters = new ArrayList<>(); + + for (com.alibaba.nacos.naming.core.Cluster cluster : detailedService.getClusterMap().values()) { + com.alibaba.nacos.api.naming.pojo.Cluster clusterView = new com.alibaba.nacos.api.naming.pojo.Cluster(); + clusterView.setName(cluster.getName()); + clusterView.setHealthChecker(cluster.getHealthChecker()); + clusterView.setMetadata(cluster.getMetadata()); + clusterView.setUseIPPort4Check(cluster.isUseIPPort4Check()); + clusterView.setDefaultPort(cluster.getDefaultPort()); + clusterView.setDefaultCheckPort(cluster.getDefaultCheckPort()); + clusterView.setServiceName(cluster.getService().getName()); + clusters.add(clusterView); + } + + detailView.replace("clusters", JacksonUtils.transferToJsonNode(clusters)); + + return detailView; + } + + @Override + public List listInstances(String namespaceId, String groupName, String serviceName, + String clusterName) throws NacosException { + Service service = serviceManager.getService(namespaceId, serviceName); + if (service == null) { + throw new NacosException(NacosException.NOT_FOUND, + String.format("service %s@@%s is not found!", groupName, serviceName)); + } + if (!service.getClusterMap().containsKey(clusterName)) { + throw new NacosException(NacosException.NOT_FOUND, "cluster " + clusterName + " is not found!"); + } + return service.getClusterMap().get(clusterName).allIPs(); + } + + @Override + public Object pageListService(String namespaceId, String groupName, String serviceName, int pageNo, int pageSize, + String instancePattern, boolean ignoreEmptyService) throws NacosException { + String param = StringUtils.isBlank(serviceName) && StringUtils.isBlank(groupName) ? StringUtils.EMPTY + : NamingUtils.getGroupedName(serviceName, groupName); + ObjectNode result = JacksonUtils.createEmptyJsonNode(); + + List services = new ArrayList<>(); + final int total = serviceManager + .getPagedService(namespaceId, pageNo - 1, pageSize, param, instancePattern, services, + ignoreEmptyService); + if (CollectionUtils.isEmpty(services)) { + result.replace("serviceList", JacksonUtils.transferToJsonNode(Collections.emptyList())); + result.put("count", 0); + return result; + } + + List serviceViews = new LinkedList<>(); + for (Service each : services) { + ServiceView serviceView = new ServiceView(); + serviceView.setName(NamingUtils.getServiceName(each.getName())); + serviceView.setGroupName(NamingUtils.getGroupName(each.getName())); + serviceView.setClusterCount(each.getClusterMap().size()); + serviceView.setIpCount(each.allIPs().size()); + serviceView.setHealthyInstanceCount(each.healthyInstanceCount()); + serviceView.setTriggerFlag(each.triggerFlag() ? "true" : "false"); + serviceViews.add(serviceView); + } + + result.set("serviceList", JacksonUtils.transferToJsonNode(serviceViews)); + result.put("count", total); + + return result; + } + + @Override + public Object pageListServiceDetail(String namespaceId, String groupName, String serviceName, int pageNo, + int pageSize) throws NacosException { + String param = StringUtils.isBlank(serviceName) && StringUtils.isBlank(groupName) ? StringUtils.EMPTY + : NamingUtils.getGroupedName(serviceName, groupName); + List serviceDetailInfoList = new ArrayList<>(); + List services = new ArrayList<>(8); + serviceManager.getPagedService(namespaceId, pageNo, pageSize, param, StringUtils.EMPTY, services, false); + + for (Service each : services) { + ServiceDetailInfo serviceDetailInfo = new ServiceDetailInfo(); + serviceDetailInfo.setServiceName(NamingUtils.getServiceName(each.getName())); + serviceDetailInfo.setGroupName(NamingUtils.getGroupName(each.getName())); + serviceDetailInfo.setMetadata(each.getMetadata()); + + Map clusterInfoMap = getStringClusterInfoMap(each); + serviceDetailInfo.setClusterMap(clusterInfoMap); + + serviceDetailInfoList.add(serviceDetailInfo); + } + + return serviceDetailInfoList; + } + + private Map getStringClusterInfoMap(Service service) { + Map clusterInfoMap = new HashMap<>(8); + + service.getClusterMap().forEach((clusterName, cluster) -> { + + ClusterInfo clusterInfo = new ClusterInfo(); + List ipAddressInfos = getIpAddressInfos(cluster.allIPs()); + clusterInfo.setHosts(ipAddressInfos); + clusterInfoMap.put(clusterName, clusterInfo); + + }); + return clusterInfoMap; + } + + private List getIpAddressInfos(List instances) { + List ipAddressInfos = new ArrayList<>(); + + instances.forEach((ipAddress) -> { + + IpAddressInfo ipAddressInfo = new IpAddressInfo(); + ipAddressInfo.setIp(ipAddress.getIp()); + ipAddressInfo.setPort(ipAddress.getPort()); + ipAddressInfo.setMetadata(ipAddress.getMetadata()); + ipAddressInfo.setValid(ipAddress.isHealthy()); + ipAddressInfo.setWeight(ipAddress.getWeight()); + ipAddressInfo.setEnabled(ipAddress.isEnabled()); + ipAddressInfos.add(ipAddressInfo); + + }); + return ipAddressInfos; + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/CatalogServiceV2Impl.java b/naming/src/main/java/com/alibaba/nacos/naming/core/CatalogServiceV2Impl.java new file mode 100644 index 000000000..21d3eb8d5 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/CatalogServiceV2Impl.java @@ -0,0 +1,211 @@ +/* + * Copyright 1999-2020 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.naming.core; + +import com.alibaba.nacos.api.common.Constants; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.pojo.Cluster; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.pojo.ServiceInfo; +import com.alibaba.nacos.api.naming.utils.NamingUtils; +import com.alibaba.nacos.common.utils.JacksonUtils; +import com.alibaba.nacos.naming.core.v2.ServiceManager; +import com.alibaba.nacos.naming.core.v2.index.ServiceStorage; +import com.alibaba.nacos.naming.core.v2.metadata.ClusterMetadata; +import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; +import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata; +import com.alibaba.nacos.naming.core.v2.pojo.Service; +import com.alibaba.nacos.naming.pojo.ServiceView; +import com.alibaba.nacos.naming.utils.ServiceUtil; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.StringJoiner; +import java.util.stream.Collectors; + +/** + * Catalog service for v1.x . + * + * @author xiweng.yy + */ +@Component() +public class CatalogServiceV2Impl implements CatalogService { + + private final ServiceStorage serviceStorage; + + private final NamingMetadataManager metadataManager; + + public CatalogServiceV2Impl(ServiceStorage serviceStorage, NamingMetadataManager metadataManager) { + this.serviceStorage = serviceStorage; + this.metadataManager = metadataManager; + } + + @Override + public Object getServiceDetail(String namespaceId, String groupName, String serviceName) throws NacosException { + Service service = Service.newService(namespaceId, NamingUtils.getGroupName(serviceName), + NamingUtils.getServiceName(serviceName)); + if (!ServiceManager.getInstance().containSingleton(service)) { + throw new NacosException(NacosException.NOT_FOUND, + String.format("service %s@@%s is not found!", groupName, serviceName)); + } + + Optional metadata = metadataManager.getServiceMetadata(service); + ServiceMetadata detailedService = metadata.orElseGet(ServiceMetadata::new); + + ObjectNode serviceObject = JacksonUtils.createEmptyJsonNode(); + serviceObject.put("name", NamingUtils.getServiceName(serviceName)); + serviceObject.put("groupName", NamingUtils.getGroupName(serviceName)); + serviceObject.put("protectThreshold", detailedService.getProtectThreshold()); + serviceObject.replace("selector", JacksonUtils.transferToJsonNode(detailedService.getSelector())); + serviceObject.replace("metadata", JacksonUtils.transferToJsonNode(detailedService.getExtendData())); + + ObjectNode detailView = JacksonUtils.createEmptyJsonNode(); + detailView.replace("service", serviceObject); + + List clusters = new ArrayList<>(); + + for (String each : serviceStorage.getClusters(service)) { + ClusterMetadata clusterMetadata = + detailedService.getClusters().containsKey(each) ? detailedService.getClusters().get(each) + : new ClusterMetadata(); + com.alibaba.nacos.api.naming.pojo.Cluster clusterView = new Cluster(); + clusterView.setName(each); + clusterView.setHealthChecker(clusterMetadata.getHealthChecker()); + clusterView.setMetadata(clusterMetadata.getExtendData()); + clusterView.setUseIPPort4Check(clusterMetadata.isUseInstancePortForCheck()); + clusterView.setDefaultPort(80); + clusterView.setDefaultCheckPort(clusterMetadata.getHealthyCheckPort()); + clusterView.setServiceName(service.getGroupedServiceName()); + clusters.add(clusterView); + } + + detailView.replace("clusters", JacksonUtils.transferToJsonNode(clusters)); + + return detailView; + } + + @Override + public List listInstances(String namespaceId, String groupName, String serviceName, + String clusterName) throws NacosException { + Service service = Service.newService(namespaceId, groupName, serviceName); + if (!ServiceManager.getInstance().containSingleton(service)) { + throw new NacosException(NacosException.NOT_FOUND, + String.format("service %s@@%s is not found!", groupName, serviceName)); + } + if (!serviceStorage.getClusters(service).contains(clusterName)) { + throw new NacosException(NacosException.NOT_FOUND, "cluster " + clusterName + " is not found!"); + } + ServiceInfo serviceInfo = serviceStorage.getData(service); + ServiceInfo result = ServiceUtil.filterInstances(serviceInfo, clusterName, false); + return result.getHosts(); + } + + @Override + public Object pageListService(String namespaceId, String groupName, String serviceName, int pageNo, int pageSize, + String instancePattern, boolean ignoreEmptyService) throws NacosException { + ObjectNode result = JacksonUtils.createEmptyJsonNode(); + List serviceViews = new LinkedList<>(); + Collection services = patternServices(namespaceId, groupName, serviceName); + if (ignoreEmptyService) { + services = services.stream().filter(each -> 0 != serviceStorage.getData(each).ipCount()) + .collect(Collectors.toList()); + } + result.put("count", services.size()); + services = doPage(services, pageNo - 1, pageSize); + for (Service each : services) { + ServiceMetadata serviceMetadata = metadataManager.getServiceMetadata(each).orElseGet(ServiceMetadata::new); + ServiceView serviceView = new ServiceView(); + serviceView.setName(each.getName()); + serviceView.setGroupName(each.getGroup()); + serviceView.setClusterCount(serviceStorage.getClusters(each).size()); + serviceView.setIpCount(serviceStorage.getData(each).ipCount()); + serviceView.setHealthyInstanceCount(countHealthyInstance(serviceStorage.getData(each))); + serviceView.setTriggerFlag(isProtectThreshold(serviceView, serviceMetadata) ? "true" : "false"); + serviceViews.add(serviceView); + } + result.set("serviceList", JacksonUtils.transferToJsonNode(serviceViews)); + return result; + } + + private int countHealthyInstance(ServiceInfo data) { + int result = 0; + for (Instance each : data.getHosts()) { + if (each.isHealthy()) { + result++; + } + } + return result; + } + + private boolean isProtectThreshold(ServiceView serviceView, ServiceMetadata metadata) { + return (serviceView.getHealthyInstanceCount() * 1.0 / serviceView.getIpCount()) <= metadata + .getProtectThreshold(); + } + + @Override + public Object pageListServiceDetail(String namespaceId, String groupName, String serviceName, int pageNo, + int pageSize) throws NacosException { + return null; + } + + private Collection patternServices(String namespaceId, String group, String serviceName) { + boolean noFilter = StringUtils.isBlank(serviceName) && StringUtils.isBlank(group); + if (noFilter) { + return serviceStorage.getAllServicesOfNamespace(namespaceId); + } + Collection result = new LinkedList<>(); + StringJoiner regex = new StringJoiner(Constants.SERVICE_INFO_SPLITER); + regex.add(getRegexString(group)); + regex.add(getRegexString(serviceName)); + String regexString = regex.toString(); + for (Service each : serviceStorage.getAllServicesOfNamespace(namespaceId)) { + if (each.getGroupedServiceName().matches(regexString)) { + result.add(each); + } + } + return result; + } + + private String getRegexString(String target) { + return StringUtils.isBlank(target) ? Constants.ANY_PATTERN + : Constants.ANY_PATTERN + target + Constants.ANY_PATTERN; + } + + private Collection doPage(Collection services, int pageNo, int pageSize) { + if (services.size() < pageSize) { + return services; + } + Collection result = new LinkedList<>(); + int i = 0; + for (Service each : services) { + if (i++ < pageNo * pageSize) { + continue; + } + result.add(each); + if (result.size() >= pageSize) { + break; + } + } + return result; + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/index/ServiceStorage.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/index/ServiceStorage.java index 8e6be096a..28a089adc 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/index/ServiceStorage.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/index/ServiceStorage.java @@ -31,6 +31,7 @@ import org.springframework.stereotype.Component; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -55,6 +56,8 @@ public class ServiceStorage { private final ConcurrentMap serviceDataIndexes; + private final ConcurrentMap> serviceClusterIndex; + private final ConcurrentMap> namespaceServiceIndex; public ServiceStorage(ClientServiceIndexesManager serviceIndexesManager, ClientManagerDelegate clientManager, @@ -62,8 +65,9 @@ public class ServiceStorage { this.serviceIndexesManager = serviceIndexesManager; this.clientManager = clientManager; this.switchDomain = switchDomain; - serviceDataIndexes = new ConcurrentHashMap<>(); - namespaceServiceIndex = new ConcurrentHashMap<>(); + this.serviceDataIndexes = new ConcurrentHashMap<>(); + this.serviceClusterIndex = new ConcurrentHashMap<>(); + this.namespaceServiceIndex = new ConcurrentHashMap<>(); } public ServiceInfo getData(Service service) { @@ -77,16 +81,26 @@ public class ServiceStorage { result.setLastRefTime(System.currentTimeMillis()); result.setCacheMillis(switchDomain.getDefaultPushCacheMillis()); List instances = new LinkedList<>(); + Set clusters = new HashSet<>(); for (String each : serviceIndexesManager.getAllClientsRegisteredService(service)) { Optional instancePublishInfo = getInstanceInfo(each, service); - instancePublishInfo.ifPresent(publishInfo -> instances.add(parseInstance(service, publishInfo))); + if (instancePublishInfo.isPresent()) { + Instance instance = parseInstance(service, instancePublishInfo.get()); + instances.add(instance); + clusters.add(instance.getClusterName()); + } } result.setHosts(instances); serviceDataIndexes.put(service, result); + serviceClusterIndex.put(service, clusters); updateNamespaceIndex(service); return result; } + public Set getClusters(Service service) { + return serviceClusterIndex.getOrDefault(service, new HashSet<>()); + } + public Collection getAllServicesOfNamespace(String namespace) { return namespaceServiceIndex.getOrDefault(namespace, new ConcurrentHashSet<>()); } @@ -114,6 +128,7 @@ public class ServiceStorage { } result.setMetadata(instanceMetadata); result.setEphemeral(service.isEphemeral()); + result.setHealthy(instancePublishInfo.isHealthy()); return result; } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/MetadataOperation.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/MetadataOperation.java new file mode 100644 index 000000000..729490d41 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/MetadataOperation.java @@ -0,0 +1,65 @@ +/* + * Copyright 1999-2020 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.naming.core.v2.metadata; + +/** + * Metadata operation. + * + * @author xiweng.yy + */ +public class MetadataOperation { + + private String namespace; + + private String group; + + private String serviceName; + + private T metadata; + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public T getMetadata() { + return metadata; + } + + public void setMetadata(T metadata) { + this.metadata = metadata; + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NacosNamingMetadataManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataManager.java similarity index 98% rename from naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NacosNamingMetadataManager.java rename to naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataManager.java index 03b7eb2f7..15979e72f 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NacosNamingMetadataManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataManager.java @@ -29,13 +29,13 @@ import java.util.concurrent.ConcurrentMap; * @author xiweng.yy */ @Component -public class NacosNamingMetadataManager { +public class NamingMetadataManager { private final ConcurrentMap serviceMetadataMap; private final ConcurrentMap> instanceMetadataMap; - public NacosNamingMetadataManager() { + public NamingMetadataManager() { serviceMetadataMap = new ConcurrentHashMap<>(1 << 10); instanceMetadataMap = new ConcurrentHashMap<>(1 << 10); } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataOperateService.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataOperateService.java new file mode 100644 index 000000000..d8c9e3a93 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/NamingMetadataOperateService.java @@ -0,0 +1,93 @@ +/* + * Copyright 1999-2020 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.naming.core.v2.metadata; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException; +import com.alibaba.nacos.consistency.DataOperation; +import com.alibaba.nacos.consistency.SerializeFactory; +import com.alibaba.nacos.consistency.Serializer; +import com.alibaba.nacos.consistency.cp.CPProtocol; +import com.alibaba.nacos.consistency.entity.Log; +import com.alibaba.nacos.consistency.entity.Response; +import com.alibaba.nacos.core.distributed.ProtocolManager; +import com.alibaba.nacos.naming.core.v2.pojo.Service; +import com.alibaba.nacos.naming.utils.Constants; +import com.google.protobuf.ByteString; +import org.springframework.stereotype.Component; + +/** + * Nacos naming metadata operate service. + * + * @author xiweng.yy + */ +@Component +public class NamingMetadataOperateService { + + private final CPProtocol cpProtocol; + + private final Serializer serializer; + + public NamingMetadataOperateService(ProtocolManager protocolManager) { + this.cpProtocol = protocolManager.getCpProtocol(); + this.serializer = SerializeFactory.getSerializer("JSON"); + } + + /** + * Update service metadata. + * + * @param service service of metadata + * @param serviceMetadata metadata + */ + public void updateServiceMetadata(Service service, ServiceMetadata serviceMetadata) { + MetadataOperation operation = new MetadataOperation<>(); + operation.setNamespace(service.getNamespace()); + operation.setGroup(service.getGroup()); + operation.setServiceName(service.getGroupedServiceName()); + operation.setMetadata(serviceMetadata); + Log operationLog = Log.newBuilder().setGroup(Constants.SERVICE_METADATA).setType(DataOperation.CHANGE.name()) + .setData(ByteString.copyFrom(serializer.serialize(operation))).build(); + submitMetadataOperation(operationLog); + } + + /** + * Delete service metadata. + * + * @param service service of metadata + */ + public void deleteServiceMetadata(Service service) { + MetadataOperation operation = new MetadataOperation<>(); + operation.setNamespace(service.getNamespace()); + operation.setGroup(service.getGroup()); + operation.setServiceName(service.getGroupedServiceName()); + Log operationLog = Log.newBuilder().setGroup(Constants.SERVICE_METADATA).setType(DataOperation.DELETE.name()) + .setData(ByteString.copyFrom(serializer.serialize(operation))).build(); + submitMetadataOperation(operationLog); + } + + private void submitMetadataOperation(Log operationLog) { + try { + Response response = cpProtocol.submit(operationLog); + if (!response.getSuccess()) { + throw new NacosRuntimeException(NacosException.SERVER_ERROR, + "do metadata operation failed " + response.getErrMsg()); + } + } catch (Exception e) { + throw new NacosRuntimeException(NacosException.SERVER_ERROR, "do metadata operation failed", e); + } + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java index 0b879738a..dd45edb4c 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java @@ -16,9 +16,11 @@ package com.alibaba.nacos.naming.core.v2.metadata; -import com.alibaba.nacos.api.selector.SelectorType; +import com.alibaba.nacos.naming.selector.NoneSelector; +import com.alibaba.nacos.naming.selector.Selector; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** @@ -36,7 +38,7 @@ public class ServiceMetadata { /** * Type of {@link com.alibaba.nacos.naming.selector.Selector}. */ - private SelectorType selectorType = SelectorType.none; + private Selector selector = new NoneSelector(); private Map extendData = new ConcurrentHashMap<>(1); @@ -50,12 +52,12 @@ public class ServiceMetadata { this.protectThreshold = protectThreshold; } - public SelectorType getSelectorType() { - return selectorType; + public Selector getSelector() { + return selector; } - public void setSelectorType(SelectorType selectorType) { - this.selectorType = selectorType; + public void setSelector(Selector selector) { + this.selector = selector; } public Map getExtendData() { @@ -73,4 +75,22 @@ public class ServiceMetadata { public void setClusters(Map clusters) { this.clusters = clusters; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ServiceMetadata)) { + return false; + } + ServiceMetadata metadata = (ServiceMetadata) o; + return Float.compare(metadata.protectThreshold, protectThreshold) == 0 && selector == metadata.selector + && Objects.equals(extendData, metadata.extendData) && Objects.equals(clusters, metadata.clusters); + } + + @Override + public int hashCode() { + return Objects.hash(protectThreshold, selector, extendData, clusters); + } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataProcessor.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataProcessor.java new file mode 100644 index 000000000..2d77de58c --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataProcessor.java @@ -0,0 +1,102 @@ +/* + * Copyright 1999-2020 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.naming.core.v2.metadata; + +import com.alibaba.nacos.consistency.DataOperation; +import com.alibaba.nacos.consistency.SerializeFactory; +import com.alibaba.nacos.consistency.Serializer; +import com.alibaba.nacos.consistency.cp.LogProcessor4CP; +import com.alibaba.nacos.consistency.entity.GetRequest; +import com.alibaba.nacos.consistency.entity.Log; +import com.alibaba.nacos.consistency.entity.Response; +import com.alibaba.nacos.core.distributed.ProtocolManager; +import com.alibaba.nacos.naming.core.v2.pojo.Service; +import com.alibaba.nacos.naming.utils.Constants; +import com.google.protobuf.ByteString; +import org.apache.commons.lang3.reflect.TypeUtils; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.Optional; + +/** + * Service metadata processor. + * + * @author xiweng.yy + */ +@Component +public class ServiceMetadataProcessor extends LogProcessor4CP { + + private final NamingMetadataManager namingMetadataManager; + + private final Serializer serializer; + + private final Type processType; + + @SuppressWarnings("unchecked") + public ServiceMetadataProcessor(NamingMetadataManager namingMetadataManager, ProtocolManager protocolManager) { + this.namingMetadataManager = namingMetadataManager; + this.serializer = SerializeFactory.getSerializer("JSON"); + this.processType = TypeUtils.parameterize(MetadataOperation.class, ServiceMetadata.class); + protocolManager.getCpProtocol().addLogProcessors(Collections.singletonList(this)); + } + + @Override + public Response onRequest(GetRequest request) { + return null; + } + + @Override + public Response onApply(Log log) { + switch (DataOperation.valueOf(log.getOperation())) { + case ADD: + case CHANGE: + updateServiceMetadata(log.getData()); + break; + case DELETE: + deleteServiceMetadata(log.getData()); + break; + default: + return Response.newBuilder().setSuccess(false).setErrMsg("Unsupported operation " + log.getOperation()) + .build(); + } + return Response.newBuilder().setSuccess(true).build(); + } + + private void updateServiceMetadata(ByteString data) { + MetadataOperation op = serializer.deserialize(data.toByteArray(), processType); + Service service = Service.newService(op.getNamespace(), op.getGroup(), op.getServiceName()); + Optional serviceMetadata = namingMetadataManager.getServiceMetadata(service); + if (serviceMetadata.isPresent()) { + namingMetadataManager.updateServiceMetadata(service, serviceMetadata.get()); + } else { + namingMetadataManager.updateServiceMetadata(service, op.getMetadata()); + } + } + + private void deleteServiceMetadata(ByteString data) { + MetadataOperation op = serializer.deserialize(data.toByteArray(), processType); + Service service = Service.newService(op.getNamespace(), op.getGroup(), op.getServiceName()); + namingMetadataManager.removeServiceMetadata(service); + } + + @Override + public String group() { + return Constants.SERVICE_METADATA; + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/EphemeralClientOperationServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/EphemeralClientOperationServiceImpl.java index f4e403772..e69388854 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/EphemeralClientOperationServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/EphemeralClientOperationServiceImpl.java @@ -75,6 +75,7 @@ public class EphemeralClientOperationServiceImpl implements ClientOperationServi result.getExtendDatum().putAll(instance.getMetadata()); String clusterName = StringUtils.isBlank(instance.getClusterName()) ? UtilsAndCommons.DEFAULT_CLUSTER_NAME : instance.getClusterName(); + result.setHealthy(instance.isHealthy()); result.getExtendDatum().put(CommonParams.CLUSTER_NAME, clusterName); return result; } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatCheckTaskV2.java b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatCheckTaskV2.java index 76228683a..6d3413f9b 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatCheckTaskV2.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatCheckTaskV2.java @@ -19,7 +19,7 @@ package com.alibaba.nacos.naming.healthcheck.heartbeat; import com.alibaba.nacos.common.task.AbstractExecuteTask; import com.alibaba.nacos.naming.consistency.KeyBuilder; import com.alibaba.nacos.naming.core.v2.client.impl.IpPortBasedClient; -import com.alibaba.nacos.naming.core.v2.metadata.NacosNamingMetadataManager; +import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; import com.alibaba.nacos.naming.core.v2.pojo.HeartBeatInstancePublishInfo; import com.alibaba.nacos.naming.core.v2.pojo.Service; import com.alibaba.nacos.naming.healthcheck.NacosHealthCheckTask; @@ -52,8 +52,8 @@ public class ClientBeatCheckTaskV2 extends AbstractExecuteTask implements BeatCh return ApplicationUtils.getBean(GlobalConfig.class); } - public NacosNamingMetadataManager getMetadataManager() { - return ApplicationUtils.getBean(NacosNamingMetadataManager.class); + public NamingMetadataManager getMetadataManager() { + return ApplicationUtils.getBean(NamingMetadataManager.class); } @Override diff --git a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ExpiredInstanceChecker.java b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ExpiredInstanceChecker.java index 2ad6ebd39..327b18f3e 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ExpiredInstanceChecker.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ExpiredInstanceChecker.java @@ -24,7 +24,7 @@ import com.alibaba.nacos.common.utils.JacksonUtils; import com.alibaba.nacos.naming.core.v2.client.Client; import com.alibaba.nacos.naming.core.v2.event.client.ClientOperationEvent; import com.alibaba.nacos.naming.core.v2.metadata.InstanceMetadata; -import com.alibaba.nacos.naming.core.v2.metadata.NacosNamingMetadataManager; +import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; import com.alibaba.nacos.naming.core.v2.pojo.HeartBeatInstancePublishInfo; import com.alibaba.nacos.naming.core.v2.pojo.InstancePublishInfo; import com.alibaba.nacos.naming.core.v2.pojo.Service; @@ -65,7 +65,7 @@ public class ExpiredInstanceChecker implements InstanceBeatChecker { } private Optional getTimeoutFromMetadata(Service service, InstancePublishInfo instance) { - Optional instanceMetadata = ApplicationUtils.getBean(NacosNamingMetadataManager.class) + Optional instanceMetadata = ApplicationUtils.getBean(NamingMetadataManager.class) .getInstanceMetadata(service, instance.getIp()); return instanceMetadata.map(metadata -> metadata.getExtendData().get(PreservedMetadataKeys.IP_DELETE_TIMEOUT)); } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/InstanceEnableBeatCheckInterceptor.java b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/InstanceEnableBeatCheckInterceptor.java index 9aef410a4..73c1aebd6 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/InstanceEnableBeatCheckInterceptor.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/InstanceEnableBeatCheckInterceptor.java @@ -18,7 +18,7 @@ package com.alibaba.nacos.naming.healthcheck.heartbeat; import com.alibaba.nacos.common.utils.ConvertUtils; import com.alibaba.nacos.naming.core.v2.metadata.InstanceMetadata; -import com.alibaba.nacos.naming.core.v2.metadata.NacosNamingMetadataManager; +import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; import com.alibaba.nacos.naming.core.v2.pojo.HeartBeatInstancePublishInfo; import com.alibaba.nacos.naming.misc.UtilsAndCommons; import com.alibaba.nacos.sys.utils.ApplicationUtils; @@ -34,7 +34,7 @@ public class InstanceEnableBeatCheckInterceptor extends AbstractBeatCheckInterce @Override public boolean intercept(InstanceBeatCheckTask object) { - NacosNamingMetadataManager metadataManager = ApplicationUtils.getBean(NacosNamingMetadataManager.class); + NamingMetadataManager metadataManager = ApplicationUtils.getBean(NamingMetadataManager.class); HeartBeatInstancePublishInfo instance = object.getInstancePublishInfo(); Optional metadata = metadataManager.getInstanceMetadata(object.getService(), instance.getIp()); if (metadata.isPresent() && metadata.get().getExtendData().containsKey(UtilsAndCommons.ENABLE_CLIENT_BEAT)) { diff --git a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ServiceEnableBeatCheckInterceptor.java b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ServiceEnableBeatCheckInterceptor.java index 7410446c5..dc8677abc 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ServiceEnableBeatCheckInterceptor.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ServiceEnableBeatCheckInterceptor.java @@ -16,7 +16,7 @@ package com.alibaba.nacos.naming.healthcheck.heartbeat; -import com.alibaba.nacos.naming.core.v2.metadata.NacosNamingMetadataManager; +import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata; import com.alibaba.nacos.naming.misc.UtilsAndCommons; import com.alibaba.nacos.sys.utils.ApplicationUtils; @@ -32,7 +32,7 @@ public class ServiceEnableBeatCheckInterceptor extends AbstractBeatCheckIntercep @Override public boolean intercept(InstanceBeatCheckTask object) { - NacosNamingMetadataManager metadataManager = ApplicationUtils.getBean(NacosNamingMetadataManager.class); + NamingMetadataManager metadataManager = ApplicationUtils.getBean(NamingMetadataManager.class); Optional metadata = metadataManager.getServiceMetadata(object.getService()); if (metadata.isPresent() && metadata.get().getExtendData().containsKey(UtilsAndCommons.ENABLE_CLIENT_BEAT)) { return Boolean.parseBoolean(metadata.get().getExtendData().get(UtilsAndCommons.ENABLE_CLIENT_BEAT)); diff --git a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/UnhealthyInstanceChecker.java b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/UnhealthyInstanceChecker.java index 0ed8e1b7d..eefb9aaa7 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/UnhealthyInstanceChecker.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/UnhealthyInstanceChecker.java @@ -25,7 +25,7 @@ import com.alibaba.nacos.naming.core.v2.client.Client; import com.alibaba.nacos.naming.core.v2.event.client.ClientEvent; import com.alibaba.nacos.naming.core.v2.event.service.ServiceEvent; import com.alibaba.nacos.naming.core.v2.metadata.InstanceMetadata; -import com.alibaba.nacos.naming.core.v2.metadata.NacosNamingMetadataManager; +import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; import com.alibaba.nacos.naming.core.v2.pojo.HeartBeatInstancePublishInfo; import com.alibaba.nacos.naming.core.v2.pojo.InstancePublishInfo; import com.alibaba.nacos.naming.core.v2.pojo.Service; @@ -65,7 +65,7 @@ public class UnhealthyInstanceChecker implements InstanceBeatChecker { } private Optional getTimeoutFromMetadata(Service service, InstancePublishInfo instance) { - Optional instanceMetadata = ApplicationUtils.getBean(NacosNamingMetadataManager.class) + Optional instanceMetadata = ApplicationUtils.getBean(NamingMetadataManager.class) .getInstanceMetadata(service, instance.getIp()); return instanceMetadata.map(metadata -> metadata.getExtendData().get(PreservedMetadataKeys.HEART_BEAT_TIMEOUT)); } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/utils/Constants.java b/naming/src/main/java/com/alibaba/nacos/naming/utils/Constants.java index 45cf3f795..74e0aab62 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/utils/Constants.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/utils/Constants.java @@ -24,7 +24,7 @@ package com.alibaba.nacos.naming.utils; */ public final class Constants { - private Constants() {} + public static final String SERVICE_METADATA = "naming_service_metadata"; public static final String NAMING_PERSISTENT_SERVICE_GROUP = "naming_persistent_service"; diff --git a/naming/src/test/java/com/alibaba/nacos/naming/controllers/CatalogControllerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/controllers/CatalogControllerTest.java index 5a50ca46a..0372c4f33 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/controllers/CatalogControllerTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/controllers/CatalogControllerTest.java @@ -67,7 +67,7 @@ public class CatalogControllerTest { @Test public void testServiceDetail() throws Exception { - ObjectNode result = catalogController.serviceDetail(Constants.DEFAULT_NAMESPACE_ID, + Object result = catalogController.serviceDetail(Constants.DEFAULT_NAMESPACE_ID, TEST_GROUP_NAME + Constants.SERVICE_INFO_SPLITER + TEST_SERVICE_NAME); String actual = result.toString(); assertTrue(actual.contains("\"service\":{")); diff --git a/naming/src/test/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatCheckTaskV2Test.java b/naming/src/test/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatCheckTaskV2Test.java index 6503bd338..e94a35d89 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatCheckTaskV2Test.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatCheckTaskV2Test.java @@ -20,7 +20,7 @@ import com.alibaba.nacos.api.naming.PreservedMetadataKeys; import com.alibaba.nacos.naming.consistency.KeyBuilder; import com.alibaba.nacos.naming.core.v2.client.impl.IpPortBasedClient; import com.alibaba.nacos.naming.core.v2.metadata.InstanceMetadata; -import com.alibaba.nacos.naming.core.v2.metadata.NacosNamingMetadataManager; +import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; import com.alibaba.nacos.naming.core.v2.pojo.HeartBeatInstancePublishInfo; import com.alibaba.nacos.naming.core.v2.pojo.Service; import com.alibaba.nacos.naming.misc.GlobalConfig; @@ -58,7 +58,7 @@ public class ClientBeatCheckTaskV2Test { private ClientBeatCheckTaskV2 beatCheckTask; @Mock - private NacosNamingMetadataManager nacosNamingMetadataManager; + private NamingMetadataManager namingMetadataManager; @Mock private GlobalConfig globalConfig; @@ -70,7 +70,7 @@ public class ClientBeatCheckTaskV2Test { @Before public void setUp() throws Exception { - when(applicationContext.getBean(NacosNamingMetadataManager.class)).thenReturn(nacosNamingMetadataManager); + when(applicationContext.getBean(NamingMetadataManager.class)).thenReturn(namingMetadataManager); when(applicationContext.getBean(GlobalConfig.class)).thenReturn(globalConfig); ApplicationUtils.injectContext(applicationContext); client = new IpPortBasedClient(CLIENT_ID, true); @@ -139,7 +139,7 @@ public class ClientBeatCheckTaskV2Test { Service service = Service.newService(NAMESPACE, GROUP_NAME, SERVICE_NAME); InstanceMetadata metadata = new InstanceMetadata(); metadata.getExtendData().put(PreservedMetadataKeys.HEART_BEAT_TIMEOUT, 1000L); - when(nacosNamingMetadataManager.getInstanceMetadata(service, IP)).thenReturn(Optional.of(metadata)); + when(namingMetadataManager.getInstanceMetadata(service, IP)).thenReturn(Optional.of(metadata)); when(globalConfig.isExpireInstance()).thenReturn(true); TimeUnit.SECONDS.sleep(1); beatCheckTask.run(); diff --git a/naming/src/test/java/com/alibaba/nacos/naming/healthcheck/interceptor/HealthCheckTaskInterceptWrapperTest.java b/naming/src/test/java/com/alibaba/nacos/naming/healthcheck/interceptor/HealthCheckTaskInterceptWrapperTest.java index d410d7a50..bd3a78191 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/healthcheck/interceptor/HealthCheckTaskInterceptWrapperTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/healthcheck/interceptor/HealthCheckTaskInterceptWrapperTest.java @@ -20,7 +20,7 @@ import com.alibaba.nacos.api.naming.PreservedMetadataKeys; import com.alibaba.nacos.naming.core.DistroMapper; import com.alibaba.nacos.naming.core.v2.client.impl.IpPortBasedClient; import com.alibaba.nacos.naming.core.v2.metadata.InstanceMetadata; -import com.alibaba.nacos.naming.core.v2.metadata.NacosNamingMetadataManager; +import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; import com.alibaba.nacos.naming.core.v2.pojo.HeartBeatInstancePublishInfo; import com.alibaba.nacos.naming.core.v2.pojo.Service; import com.alibaba.nacos.naming.healthcheck.heartbeat.ClientBeatCheckTaskV2; @@ -61,7 +61,7 @@ public class HealthCheckTaskInterceptWrapperTest { private HealthCheckTaskInterceptWrapper taskWrapper; @Mock - private NacosNamingMetadataManager nacosNamingMetadataManager; + private NamingMetadataManager namingMetadataManager; @Mock private GlobalConfig globalConfig; @@ -79,7 +79,7 @@ public class HealthCheckTaskInterceptWrapperTest { @Before public void setUp() throws Exception { - when(applicationContext.getBean(NacosNamingMetadataManager.class)).thenReturn(nacosNamingMetadataManager); + when(applicationContext.getBean(NamingMetadataManager.class)).thenReturn(namingMetadataManager); when(applicationContext.getBean(GlobalConfig.class)).thenReturn(globalConfig); when(applicationContext.getBean(SwitchDomain.class)).thenReturn(switchDomain); when(applicationContext.getBean(DistroMapper.class)).thenReturn(distroMapper); @@ -162,7 +162,7 @@ public class HealthCheckTaskInterceptWrapperTest { Service service = Service.newService(NAMESPACE, GROUP_NAME, SERVICE_NAME); InstanceMetadata metadata = new InstanceMetadata(); metadata.getExtendData().put(PreservedMetadataKeys.HEART_BEAT_TIMEOUT, 1000L); - when(nacosNamingMetadataManager.getInstanceMetadata(service, IP)).thenReturn(Optional.of(metadata)); + when(namingMetadataManager.getInstanceMetadata(service, IP)).thenReturn(Optional.of(metadata)); when(globalConfig.isExpireInstance()).thenReturn(true); TimeUnit.SECONDS.sleep(1); taskWrapper.run(); diff --git a/pom.xml b/pom.xml index 1cb363ea3..412053ae1 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 2018 com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT pom Alibaba NACOS ${project.version} @@ -36,7 +36,7 @@ git@github.com:alibaba/nacos.git scm:git@github.com:alibaba/nacos.git scm:git@github.com:alibaba/nacos.git - nacos-all-2.0.0-ALPHA + nacos-all-2.0.0-SNAPSHOT diff --git a/sys/pom.xml b/sys/pom.xml index b3b1d6cf8..79a07082e 100644 --- a/sys/pom.xml +++ b/sys/pom.xml @@ -21,7 +21,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT ../pom.xml 4.0.0 diff --git a/test/pom.xml b/test/pom.xml index d902a333e..be5b40d3e 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -20,7 +20,7 @@ com.alibaba.nacos nacos-all - 2.0.0-ALPHA + 2.0.0-SNAPSHOT ../pom.xml 4.0.0