You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by GitBox <gi...@apache.org> on 2018/08/17 06:44:23 UTC

[GitHub] beiwei30 closed pull request #2290: [Dubbo-config]A port conflict problem of dubbo provider when multiple services start concurrentl

beiwei30 closed pull request #2290: [Dubbo-config]A port conflict problem of dubbo provider when multiple services start concurrentl
URL: https://github.com/apache/incubator-dubbo/pull/2290
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
index a1c8fac34c..5b9add9407 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java
@@ -644,5 +644,5 @@
     /*
      * private Constants(){ }
      */
-
+    public static final String RANDOM_PORT = "random.port";
 }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
index e9d5e6b567..3376f1c12f 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
@@ -30,11 +30,7 @@
 import org.apache.dubbo.config.model.ApplicationModel;
 import org.apache.dubbo.config.model.ProviderModel;
 import org.apache.dubbo.config.support.Parameter;
-import org.apache.dubbo.rpc.Exporter;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Protocol;
-import org.apache.dubbo.rpc.ProxyFactory;
-import org.apache.dubbo.rpc.ServiceClassHolder;
+import org.apache.dubbo.rpc.*;
 import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
 import org.apache.dubbo.rpc.service.GenericService;
 import org.apache.dubbo.rpc.support.ProtocolUtils;
@@ -204,7 +200,6 @@ public synchronized void export() {
         if (export != null && !export) {
             return;
         }
-
         if (delay != null && delay > 0) {
             delayExportExecutor.schedule(new Runnable() {
                 @Override
@@ -351,11 +346,40 @@ public synchronized void unexport() {
         unexported = true;
     }
 
+    private static void removeRandomPort(String protocol) {
+        protocol = protocol.toLowerCase();
+        RANDOM_PORT_MAP.remove(protocol);
+    }
+
+    private String getProtocolName(ProtocolConfig protocolConfig) {
+        String name = protocolConfig.getName();
+        if (name == null || name.length() == 0) {
+            name = "dubbo";
+        }
+        return name;
+    }
+
     @SuppressWarnings({"unchecked", "rawtypes"})
     private void doExportUrls() {
         List<URL> registryURLs = loadRegistries(true);
         for (ProtocolConfig protocolConfig : protocols) {
-            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
+            while (true) {
+                try {
+                    doExportUrlsFor1Protocol(protocolConfig, registryURLs);
+                    break;
+                } catch (RpcException e) {
+                    if (StringUtils.isEquals(e.getMessage(), "random port is occupied")) {
+                        logger.error("doExportUrls port failure and try again: " + e.getMessage(), e);
+                        removeRandomPort(getProtocolName(protocolConfig));
+                        try {
+                            Thread.sleep(1000);
+                        } catch (InterruptedException ignored) {
+                        }
+                    } else {
+                        throw e;
+                    }
+                }
+            }
         }
     }
 
@@ -479,47 +503,59 @@ private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> r
 
         String scope = url.getParameter(Constants.SCOPE_KEY);
         // don't export when none is configured
-        if (!Constants.SCOPE_NONE.equalsIgnoreCase(scope)) {
+        try {
+            if (!Constants.SCOPE_NONE.equalsIgnoreCase(scope)) {
 
-            // export to local if the config is not remote (export to remote only when config is remote)
-            if (!Constants.SCOPE_REMOTE.equalsIgnoreCase(scope)) {
-                exportLocal(url);
-            }
-            // export to remote if the config is not local (export to local only when config is local)
-            if (!Constants.SCOPE_LOCAL.equalsIgnoreCase(scope)) {
-                if (logger.isInfoEnabled()) {
-                    logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
+                // export to local if the config is not remote (export to remote only when config is remote)
+                if (!Constants.SCOPE_REMOTE.equalsIgnoreCase(scope)) {
+                    exportLocal(url);
                 }
-                if (registryURLs != null && !registryURLs.isEmpty()) {
-                    for (URL registryURL : registryURLs) {
-                        url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
-                        URL monitorUrl = loadMonitor(registryURL);
-                        if (monitorUrl != null) {
-                            url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
-                        }
-                        if (logger.isInfoEnabled()) {
-                            logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
-                        }
+                // export to remote if the config is not local (export to local only when config is local)
+                if (!Constants.SCOPE_LOCAL.equalsIgnoreCase(scope)) {
+                    if (logger.isInfoEnabled()) {
+                        logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
+                    }
+                    if (registryURLs != null && !registryURLs.isEmpty()) {
+                        for (URL registryURL : registryURLs) {
+                            url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
+                            URL monitorUrl = loadMonitor(registryURL);
+                            if (monitorUrl != null) {
+                                url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
+                            }
+                            if (logger.isInfoEnabled()) {
+                                logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
+                            }
 
-                        // For providers, this is used to enable custom proxy to generate invoker
-                        String proxy = url.getParameter(Constants.PROXY_KEY);
-                        if (StringUtils.isNotEmpty(proxy)) {
-                            registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
-                        }
+                            // For providers, this is used to enable custom proxy to generate invoker
+                            String proxy = url.getParameter(Constants.PROXY_KEY);
+                            if (StringUtils.isNotEmpty(proxy)) {
+                                registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
+                            }
 
-                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
+                            Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
+                            DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
+
+                            Exporter<?> exporter = protocol.export(wrapperInvoker);
+                            exporters.add(exporter);
+                        }
+                    } else {
+                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                         DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
 
                         Exporter<?> exporter = protocol.export(wrapperInvoker);
                         exporters.add(exporter);
                     }
+                }
+            }
+        } catch (RpcException e) {
+            if (e.getMessage().contains("Failed to bind")) {
+                if (StringUtils.isBlank(map.get(Constants.RANDOM_PORT))) {
+                    throw new RpcException("port is occupied");
                 } else {
-                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
-                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
-
-                    Exporter<?> exporter = protocol.export(wrapperInvoker);
-                    exporters.add(exporter);
+                    throw new RpcException("random port is occupied");
                 }
+            } else {
+                throw e;
             }
         }
         this.urls.add(url);
@@ -654,6 +690,7 @@ private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Ma
                 if (portToBind == null || portToBind < 0) {
                     portToBind = getAvailablePort(defaultPort);
                     putRandomPort(name, portToBind);
+                    map.put(Constants.RANDOM_PORT, String.valueOf(portToBind));
                 }
                 logger.warn("Use random available port(" + portToBind + ") for protocol " + name);
             }
diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml
index c2ab4a21e0..900588a7dd 100644
--- a/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml
+++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/META-INF/spring/dubbo-demo-provider.xml
@@ -28,7 +28,7 @@
     <dubbo:registry address="multicast://224.5.6.7:1234"/>
 
     <!-- use dubbo protocol to export service on port 20880 -->
-    <dubbo:protocol name="dubbo" port="20880"/>
+    <dubbo:protocol name="dubbo" port="-1"/>
 
     <!-- service implementation, as same as regular local bean -->
     <bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
diff --git a/dubbo-demo/dubbo-demo-provider/src/main/resources/dubbo.properties b/dubbo-demo/dubbo-demo-provider/src/main/resources/dubbo.properties
index ad602baa94..ca71826c80 100644
--- a/dubbo-demo/dubbo-demo-provider/src/main/resources/dubbo.properties
+++ b/dubbo-demo/dubbo-demo-provider/src/main/resources/dubbo.properties
@@ -1 +1 @@
-dubbo.application.qos.port=22222
+dubbo.application.qos.port=22222
\ No newline at end of file


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org