Dubbo Rpc 使用随机端口
dubbo在进行服务间通信的时候需要使用端口进行通信, 但是这个端口的指定规则是什么。
随机端口生成方式
查看源码定位到dubbo获取端口的方法在 doExportUrlsFor1Protocol
此方法中关于端口的代码如下:
//从dubbo:protocol标签中读取port配置
Integer port = protocolConfig.getPort();
//如果有provider标签配置,且protocol中port配置为null 或者 0,则直接使用provider中的port端口
if (this.provider != null && (port == null || port == 0)) {
port = this.provider.getPort();
}
//根据协议类型获取默认端口号(默认端口为20880)
int defaultPort = ((Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name)).getDefaultPort();
//如果配置port为null或者0,则会使用默认端口
if (port == null || port == 0) {
port = defaultPort;
}
//如果配置port为null或者小于0(例如-1)则使用自动端口
if (port == null || port <= 0) {
//获取随机端口,从缓存中取
port = getRandomPort(name);
//如果获取端口为空,则以默认端口为基准,按顺序取最近一个可用的端口
if (port == null || port < 0) {
port = NetUtils.getAvailablePort(defaultPort);
//添加到随机端口的port的map
putRandomPort(name, port);
}
logger.warn("Use random available port(" + port + ") for protocol " + name);
}
进一步查看NetUtils.getAvailablePort(defaultPort)方法,代码如下:
public static int getAvailablePort(int port) {
if (port <= 0) {
return getAvailablePort();
} else {
for(int i = port; i < 65535; ++i) {
ServerSocket ss = null;
//循环创建端口,假如端口被占用抛出异常并继续循环
//当获取到可用端口后返回
try {
ss = new ServerSocket(i);
int var5 = i;
return var5;
} catch (IOException var13) {
} finally {
if (ss != null) {
try {
ss.close();
} catch (IOException var12) {
}
}
}
}
return port;
}
}
查看使用了哪些端口
lsof -i|grep 5083(dubbo服务进程)|grep LISTEN
使用固定还是随机
需要注意的是,dubbo文档的推荐用法指出:
使用固定端口暴露服务,而不要使用随机端口
这样在注册中心推送有延迟的情况下,消费者通过缓存列表也能调用到原地址,保证调用成功。
我理解的场景是假如我们使用随机端口,启动了提供者,假如我们使用随机端口,随机到的端口20880, 那么注册中心提供给消费者的端口为20080;当我们因为要更新提供者,并将提供者重启并使用了随机端口的方式,那么这次端口为30080,因为注册中心通知延迟,可能使用30080的提供者已经启动完毕,但是消费者没有收到通知,所以依然使用缓存的20080调用就会出错。
那么使用固定端口20080就不会有这个问题。
但是考虑实际场景和配置的复杂度,我们对接口调用的实时性应该是没有这么高的。
假如后期使用了容器化,每个dubbo应用作为一个容器的话,端口问题也可以得到比较好的解决。