You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by ra...@apache.org on 2021/09/03 03:15:35 UTC

[dubbo-admin] branch develop updated: Nacos support application discover (#812)

This is an automated email from the ASF dual-hosted git repository.

ranke pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git


The following commit(s) were added to refs/heads/develop by this push:
     new 237fd26  Nacos support application discover (#812)
237fd26 is described below

commit 237fd266a686e70b359ccf2ff8b2311d0b3ebdc5
Author: haoyann <10...@qq.com>
AuthorDate: Fri Sep 3 11:13:33 2021 +0800

    Nacos support application discover (#812)
---
 .../apache/dubbo/admin/common/util/SyncUtils.java  |  14 +-
 .../registry/mapping/impl/NacosServiceMapping.java | 170 +++++++++++++++++++++
 .../dubbo/admin/service/RegistryServerSync.java    |  17 ++-
 ...che.dubbo.admin.registry.mapping.ServiceMapping |   3 +-
 4 files changed, 197 insertions(+), 7 deletions(-)

diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java
index 88e9e73..7a36c0b 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java
@@ -21,6 +21,7 @@ import org.apache.dubbo.admin.model.domain.Provider;
 import org.apache.dubbo.admin.model.domain.RegistrySource;
 import org.apache.dubbo.common.BaseServiceMetadata;
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.StringUtils;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -52,7 +53,7 @@ public class SyncUtils {
         p.setHash(id);
         String group = url.getUrlParam().getParameter(Constants.GROUP_KEY);
         String version = url.getUrlParam().getParameter(Constants.VERSION_KEY);
-        String service = BaseServiceMetadata.buildServiceKey(url.getServiceInterface(), group, version);
+        String service = BaseServiceMetadata.buildServiceKey(getServiceInterface(url), group, version);
         p.setService(service);
         p.setAddress(url.getAddress());
         p.setApplication(url.getParameter(Constants.APPLICATION_KEY));
@@ -91,7 +92,7 @@ public class SyncUtils {
         c.setHash(id);
         String group = url.getUrlParam().getParameter(Constants.GROUP_KEY);
         String version = url.getUrlParam().getParameter(Constants.VERSION_KEY);
-        String service = BaseServiceMetadata.buildServiceKey(url.getServiceInterface(), group, version);
+        String service = BaseServiceMetadata.buildServiceKey(getServiceInterface(url), group, version);
         c.setService(service);
         c.setAddress(url.getHost());
         c.setApplication(url.getParameter(Constants.APPLICATION_KEY));
@@ -188,4 +189,13 @@ public class SyncUtils {
         }
         return null;
     }
+
+    private static String getServiceInterface(URL url) {
+        String serviceInterface = url.getServiceInterface();
+        if (StringUtils.isBlank(serviceInterface) || Constants.ANY_VALUE.equals(serviceInterface)) {
+            serviceInterface = url.getPath();
+        }
+        return serviceInterface;
+    }
+
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/NacosServiceMapping.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/NacosServiceMapping.java
new file mode 100644
index 0000000..6749da6
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/NacosServiceMapping.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.dubbo.admin.registry.mapping.impl;
+
+import org.apache.dubbo.admin.registry.mapping.ServiceMapping;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.ConcurrentHashSet;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.metadata.MappingChangedEvent;
+import org.apache.dubbo.metadata.MappingListener;
+import org.apache.dubbo.registry.nacos.NacosNamingServiceWrapper;
+import org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils;
+
+import com.alibaba.nacos.api.common.Constants;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.alibaba.nacos.api.naming.pojo.ListView;
+import com.google.common.collect.Sets;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_LOAD_CACHE_AT_START;
+import static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;
+import static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;
+import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
+import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;
+
+/**
+ * Nacos not support batch listen config feature. Therefore, regularly query the service list instead of notification
+ */
+public class NacosServiceMapping implements ServiceMapping {
+
+    /**
+     * All 2.x supported categories
+     */
+    private static final List<String> ALL_SUPPORTED_CATEGORIES = Arrays.asList(
+            PROVIDERS_CATEGORY,
+            CONSUMERS_CATEGORY,
+            ROUTERS_CATEGORY,
+            CONFIGURATORS_CATEGORY
+    );
+
+    /**
+     * The separator for service name
+     * Change a constant to be configurable, it's designed for Windows file name that is compatible with old
+     * Nacos binary release(< 0.6.1)
+     */
+    private static final String SERVICE_NAME_SEPARATOR = System.getProperty("nacos.service.name.separator", ":");
+
+    private static final long LOOKUP_INTERVAL = Long.getLong("nacos.service.names.lookup.interval", 30);
+
+    private ScheduledExecutorService scheduledExecutorService;
+
+    private final Set<MappingListener> listeners = new ConcurrentHashSet<>();
+
+    private static final int PAGINATION_SIZE = 100;
+
+    private NacosNamingServiceWrapper namingService;
+
+    private Set<String> anyServices = new HashSet<>();
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(NacosServiceMapping.class);
+
+    @Override
+    public void init(URL url) {
+        url.addParameter(NAMING_LOAD_CACHE_AT_START, "false");
+        namingService = NacosNamingServiceUtils.createNamingService(url);
+        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
+        listenerAll();
+    }
+
+    @Override
+    public void listenerAll() {
+
+        try {
+            anyServices = getAllServiceNames();
+        } catch (Exception e) {
+            LOGGER.error("Get nacos all services fail ", e);
+        }
+        for (String service : anyServices) {
+            notifyMappingChangedEvent(service);
+        }
+        scheduledExecutorService.scheduleAtFixedRate(() -> {
+            try {
+                Set<String> serviceNames = getAllServiceNames();
+                for (String serviceName : serviceNames) {
+                    if (anyServices.add(serviceName)) {
+                        notifyMappingChangedEvent(serviceName);
+                    }
+                }
+            } catch (Exception e) {
+                LOGGER.error("Get nacos all services fail ", e);
+            }
+
+        }, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS);
+    }
+
+    private Set<String> getAllServiceNames() throws NacosException {
+
+        Set<String> serviceNames = new HashSet<>();
+        int pageIndex = 1;
+        ListView<String> listView = namingService.getServicesOfServer(pageIndex, PAGINATION_SIZE,
+                Constants.DEFAULT_GROUP);
+        // First page data
+        List<String> firstPageData = listView.getData();
+        // Append first page into list
+        serviceNames.addAll(firstPageData);
+        // the total count
+        int count = listView.getCount();
+        // the number of pages
+        int pageNumbers = count / PAGINATION_SIZE;
+        int remainder = count % PAGINATION_SIZE;
+        // remain
+        if (remainder > 0) {
+            pageNumbers += 1;
+        }
+        // If more than 1 page
+        while (pageIndex < pageNumbers) {
+            listView = namingService.getServicesOfServer(++pageIndex, PAGINATION_SIZE, Constants.DEFAULT_GROUP);
+            serviceNames.addAll(listView.getData());
+        }
+
+        return serviceNames;
+    }
+
+    private void notifyMappingChangedEvent(String service) {
+        if (StringUtils.isBlank(service)) {
+            return;
+        }
+        for (String category : ALL_SUPPORTED_CATEGORIES) {
+            String prefix = category + SERVICE_NAME_SEPARATOR;
+            if (service.startsWith(prefix)) {
+                return;
+            }
+        }
+        MappingChangedEvent event = new MappingChangedEvent(null, Sets.newHashSet(service));
+        for (MappingListener listener : listeners) {
+            listener.onEvent(event);
+        }
+    }
+
+
+    @Override
+    public void addMappingListener(MappingListener listener) {
+        listeners.add(listener);
+    }
+
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
index dab1a43..475bb31 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
@@ -110,11 +110,11 @@ public class RegistryServerSync implements DisposableBean, NotifyListener {
                     String version = url.getUrlParam().getParameter(Constants.VERSION_KEY);
                     // NOTE: group and version in empty protocol is *
                     if (!Constants.ANY_VALUE.equals(group) && !Constants.ANY_VALUE.equals(version)) {
-                        services.remove(url.getServiceInterface());
+                        services.remove(getServiceInterface(url));
                     } else {
                         for (Map.Entry<String, Map<String, URL>> serviceEntry : services.entrySet()) {
                             String service = serviceEntry.getKey();
-                            if (Tool.getInterface(service).equals(url.getServiceInterface())
+                            if (Tool.getInterface(service).equals(getServiceInterface(url))
                                     && (Constants.ANY_VALUE.equals(group) || StringUtils.isEquals(group, Tool.getGroup(service)))
                                     && (Constants.ANY_VALUE.equals(version) || StringUtils.isEquals(version, Tool.getVersion(service)))) {
                                 services.remove(service);
@@ -124,7 +124,7 @@ public class RegistryServerSync implements DisposableBean, NotifyListener {
                 }
             } else {
                 if (StringUtils.isEmpty(interfaceName)) {
-                    interfaceName = url.getServiceInterface();
+                    interfaceName = getServiceInterface(url);
                 }
                 Map<String, Map<String, URL>> services = categories.get(category);
                 if (services == null) {
@@ -133,7 +133,7 @@ public class RegistryServerSync implements DisposableBean, NotifyListener {
                 }
                 String group = url.getUrlParam().getParameter(Constants.GROUP_KEY);
                 String version = url.getUrlParam().getParameter(Constants.VERSION_KEY);
-                String service = BaseServiceMetadata.buildServiceKey(url.getServiceInterface(), group, version);
+                String service = BaseServiceMetadata.buildServiceKey(getServiceInterface(url), group, version);
                 Map<String, URL> ids = services.get(service);
                 if (ids == null) {
                     ids = new HashMap<>();
@@ -170,5 +170,14 @@ public class RegistryServerSync implements DisposableBean, NotifyListener {
             services.putAll(categoryEntry.getValue());
         }
     }
+
+    private String getServiceInterface(URL url) {
+        String serviceInterface = url.getServiceInterface();
+        if (StringUtils.isBlank(serviceInterface) || Constants.ANY_VALUE.equals(serviceInterface)) {
+            serviceInterface = url.getPath();
+        }
+        return serviceInterface;
+    }
+
 }
 
diff --git a/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping b/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping
index 83709e7..90c6c4a 100644
--- a/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping
+++ b/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping
@@ -1 +1,2 @@
-zookeeper=org.apache.dubbo.admin.registry.mapping.impl.ZookeeperServiceMapping
\ No newline at end of file
+zookeeper=org.apache.dubbo.admin.registry.mapping.impl.ZookeeperServiceMapping
+nacos=org.apache.dubbo.admin.registry.mapping.impl.NacosServiceMapping
\ No newline at end of file