gongstring技术博客
最新文章
源码解读
软件安装
常见问题
大数据
常用工具
鸡汤文
备案号:鄂ICP备15015839号-1
鄂公网安备 42010202001692号
通过源码教你如何开启Dubbo框架随机端口功能
2019-10-31 19:23:17
作者: gongstring
源码解读
/
通过源码教你如何开启Dubbo框架随机端口功能
## 1.业务场景 当前我们基本上一台服务器部署一个应用,所以dubbo协议端口提前配置好,例如:dubbo协议使用20880,rest协议使用20889;但是如果需要在同一台主机部署多个实例节点时,会出现端口冲突,解决方法有两种: 手工分配并修改端口;(很明显不优雅,且后期运维成本很高) 系统支持自动分配端口;(优选方案) 本文就是通过dubbo源码解读,说明如何配置才能实现第二种方案. ### 开启自动分配端口 此处以dubbox中dubbo.xml配置 ```
``` 如果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 service String 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
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) { //