通过源码教你如何开启Dubbo框架不重复可用端口功能
业务场景
当前我们基本上一台服务器部署一个应用,所以dubbo协议端口提前配置好,例如:dubbo协议使用20880,rest协议使用20889;但是如果需要在同一台主机部署多个实例节点时,会出现端口冲突,解决方法有两种:
- 手工分配并修改端口;(很明显不优雅,且后期运维成本很高)
- 系统支持自动分配端口;(优选方案)
本文就是通过dubbo源码解读,说明如何配置才能实现第二种方案.
开启自动分配端口
此处以dubbox中dubbo.xml配置
<dubbo:protocol name="rest" port="-1" /><dubbo:protocol name="dubbo" port="-1" />
如果port不填或者直接设置成null,将会使用系统默认的端口;如果设置成小于0(例如-1),则随机分配未被使用的端口。
其中dubbo协议从20880开始编起,rest协议则从80端口开始编起;
老版本dubbo框架源码
方法源码:com.alibaba.dubbo.config.ServiceConfig.doExportUrlsFor1Protocol()
该方法在dubbo容器启动,进行provider export初始化时调用,其中包括IP地址以及端口获取的逻辑,下面是端口处理的源码:
//从dubbo:protocol标签中读取port配置Integer port = protocolConfig.getPort();
//如果有provider标签配置,且protocol中port配置为null 或者 0,则直接使用provider中的port端口
if (provider != null && (port == null || port == 0)) {
port = provider.getPort();
}
//根据协议类型获取默认端口号(dubbo协议的端口为20880,源码在下面有说明)
final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
//如果配置port为null或者0,则会使用默认端口
if (port == null || port == 0) {
port = defaultPort;
}
//如果经过默认端口处理后,port为null(例如没有协议中配置默认端口)或者负数,则随机生成一个端口
if (port == null || port <= 0) {
//获取随机端口,从缓存中取
port = getRandomPort(name);
//如果获取端口为空,则以默认端口为基准,按顺序取最近一个可用的端口
if (port == null || port < 0) {
port = NetUtils.getAvailablePort(defaultPort);
//添加到缓存中
putRandomPort(name, port);
}
logger.warn("Use random available port(" + port + ") for protocol " + name);
}
下面是dubbo协议的默认端口配置:
com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
核心源码:
public static final int DEFAULT_PORT = 20880;
获取顺序可用端口源码
public static int getAvailablePort(int port) {
if (port <= 0) {
return getAvailablePort();
}
for(int i = port; i < MAX_PORT; i ++) {
ServerSocket ss = null;
try {
ss = new ServerSocket(i);
return i;
} catch (IOException e) {
// continue
} finally {
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
}
}
}
}
return port;
}
新版dubbo框架源码(Apache)
在新版dubbo框架中,从环境变量可以配置端口(优先级最高)
获取端口源码地址:
org.apache.dubbo.config.ServiceConfig.doExportUrlsFor1Protocol()
// export serviceString host = this.findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = this.findConfigedPorts(protocolConfig, name, map);
URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
org.apache.dubbo.config.ServiceConfig.findConfigedPorts()
/**
* Register port and bind port for the provider, can be configured separately
* Configuration priority: environment variable -> java system properties -> port property in protocol config file
* -> protocol default port
*
* @param protocolConfig
* @param name
* @return
*/
private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
Integer portToBind = null;
//支持从环境变量中获取端口
// parse bind port from environment
String port = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_BIND);
portToBind = parsePort(port);
//如果环境变量没有配置绑定端口,走下面逻辑
// if there"s no bind port found from environment, keep looking up.
if (portToBind == null) {
//<dubbo:protocol标签中的port端口
portToBind = protocolConfig.getPort();
if (provider != null && (portToBind == null || portToBind == 0)) {
portToBind = provider.getPort();
}
//获取默认端口:dubbo:20880,http:80(与老版本一致)
final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
//如果标签中配置端口为null或者0,则使用默认端口
if (portToBind == null || portToBind == 0) {
portToBind = defaultPort;
}
//如果配置是负数,则随机获取或按顺序获取可用端口
if (portToBind <= 0) {
//获取随机逻辑与最近可用端口逻辑(与老版本一致)
portToBind = getRandomPort(name);
if (portToBind == null || portToBind < 0) {
portToBind = getAvailablePort(defaultPort);
putRandomPort(name, portToBind);
}
}
}
// save bind port, used as url"s key later
map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));
// registry port, not used as bind port by default
String portToRegistryStr = getValueFromConfig(protocolConfig, DUBBO_PORT_TO_REGISTRY);
Integer portToRegistry = parsePort(portToRegistryStr);
if (portToRegistry == null) {
portToRegistry = portToBind;
}
return portToRegistry;
}
以上是 通过源码教你如何开启Dubbo框架不重复可用端口功能 的全部内容, 来源链接: utcz.com/z/510290.html