haigeek blog


Dubbo Rpc 使用随机端口

dubbo在进行服务间通信的时候需要使用端口进行通信,但是这个端口的指定规则是什么。

随机端口生成方式

查看源码定位到dubbo获取端口的方法在doExportUrlsFor1Protocol

此方法中关于端口的代码如下:

 1//从dubbo:protocol标签中读取port配置 
 2Integer port = protocolConfig.getPort();
 3//如果有provider标签配置,且protocol中port配置为null 或者 0,则直接使用provider中的port端口
 4        if (this.provider != null && (port == null || port == 0)) {
 5            port = this.provider.getPort();
 6        }
 7//根据协议类型获取默认端口号(默认端口为20880)
 8        int defaultPort = ((Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name)).getDefaultPort();
 9//如果配置port为null或者0,则会使用默认端口
10        if (port == null || port == 0) {
11            port = defaultPort;
12        }
13//如果配置port为null或者小于0(例如-1)则使用自动端口
14        if (port == null || port <= 0) {
15          //获取随机端口,从缓存中取
16            port = getRandomPort(name);
17          	//如果获取端口为空,则以默认端口为基准,按顺序取最近一个可用的端口
18            if (port == null || port < 0) {
19                port = NetUtils.getAvailablePort(defaultPort);
20              //添加到随机端口的port的map
21                putRandomPort(name, port);
22            }
23
24            logger.warn("Use random available port(" + port + ") for protocol " + name);
25        }

进一步查看NetUtils.getAvailablePort(defaultPort)方法,代码如下:

 1public static int getAvailablePort(int port) {
 2        if (port <= 0) {
 3            return getAvailablePort();
 4        } else {
 5            for(int i = port; i < 65535; ++i) {
 6                ServerSocket ss = null;
 7				//循环创建端口,假如端口被占用抛出异常并继续循环
 8              	//当获取到可用端口后返回
 9                try {
10                    ss = new ServerSocket(i);
11                    int var5 = i;
12                    return var5;
13                } catch (IOException var13) {
14                } finally {
15                    if (ss != null) {
16                        try {
17                            ss.close();
18                        } catch (IOException var12) {
19                        }
20                    }
21
22                }
23            }
24
25            return port;
26        }
27    }

查看使用了哪些端口

lsof -i|grep 5083(dubbo服务进程)|grep LISTEN 

使用固定还是随机

需要注意的是,dubbo文档的推荐用法指出:

使用固定端口暴露服务,而不要使用随机端口

这样在注册中心推送有延迟的情况下,消费者通过缓存列表也能调用到原地址,保证调用成功。

我理解的场景是假如我们使用随机端口,启动了提供者,假如我们使用随机端口,随机到的端口20880,那么注册中心提供给消费者的端口为20080;当我们因为要更新提供者,并将提供者重启并使用了随机端口的方式,那么这次端口为30080,因为注册中心通知延迟,可能使用30080的提供者已经启动完毕,但是消费者没有收到通知,所以依然使用缓存的20080调用就会出错。

那么使用固定端口20080就不会有这个问题。

但是考虑实际场景和配置的复杂度,我们对接口调用的实时性应该是没有这么高的。

假如后期使用了容器化,每个dubbo应用作为一个容器的话,端口问题也可以得到比较好的解决。