容器上使用DUBBO 为什么2.7.12版本 Bind端口强制使用了注册端口号,导致容器下无法正确访问
2.7.8 版本代码如下。 ServiceConfig.java 方法 findConfigedPorts 代码 map.put(BIND_PORT_KEY, String.valueOf(portToBind));
2.7.12版本代码 ServiceConfig.java 方法 findConfigedPorts 代码 map.put(BIND_PORT_KEY, String.valueOf(portToRegistry));
有什么特殊的考虑吗?
这个是为了解决这个case: #7656
把DUBBO_DUBBO_PORT_TO_BIND和DUBBO_PORT_TO_REGISTRY两个配置统一了。 如果DUBBO_PORT_TO_REGISTRY指定了就用这个;没指定就用DUBBO_DUBBO_PORT_TO_BIND。
ps:我觉得这个代码的写法确实不是很合适,如果是我会这么写:
portToBind = portToRegistry == null ? portToRegistry : portToRegistry;
map.put(BIND_PORT_KEY, String.valueOf(portToBind));
这样可读性会高一点;
我后续调整一下。
本质上逻辑和2.7.8是没区别的,只是只能用一个配置端口而已,毕竟也无法配置两个不同的端口
@changfubai
你好,这个在 容器环境下 , 使用同一个 IP , 跑多个实例 规划端口会比较麻烦。
@changfubai 你好,这个在 容器环境下 , 使用同一个 IP , 跑多个实例 规划端口会比较麻烦。
你说的是多个实例分别在不同的容器里,ip和端口怎么设计是么? 为啥会存在同一个ip,多实例用不同的端口的情况呢? 假设是我说的那种case,就用环境变量注入ip和端口可以了,容器外能访问通的地址就行
你好,我们使用的是 NodePort 模式。 注册到注册中心的是 Node 的 IP , 因此需要每一个 实例在Node 上都有唯一映射 Port(这个也是 注册到注册中心的Port) 这样才能够全部访问到。
你好,我们使用的是 NodePort 模式。 注册到注册中心的是 Node 的 IP , 因此需要每一个 实例在Node 上都有唯一映射 Port(这个也是 注册到注册中心的Port) 这样才能够全部访问到。
这种情况没什么好的办法,你要用nodePort注册就是会需要开很多端口。正常上线的服务,不需要对集群外部暴露服务的吧?那使用nodePort是基于什么考量呢
这个问题我也发现了。服务绑定的端口是容器内的端口,而上报到注册中心的端口应该是宿主机的端口。比如内部IP和端口是IP1:Port1,上报到注册中心的IP和端口应该是宿主机的IP端口,比如IP2:Port2。 容器负载配置port2映射到port1。主机外的消费者看到的服务提供者的地址是IP2:Port2。因为消费者不能直接通过IP1:Port1访问服务。将请求发给IP2:Port2,然后宿主机将其转发到内部的容器实例IP1:Port1。
dubbo这么一改后,业务配置的绑定端口port1就无效了,直接监听端口DUBBO_PORT_TO_REGISTRY,即port2了。以前端口映射配置是port2->port1,现在就变成了port2->port2了。port1就没用了。
// registry port, not used as bind port by default
String key = DUBBO_PORT_TO_REGISTRY;
if (protocolConfigNum > 1) {
key = getProtocolConfigId(protocolConfig).toUpperCase() + "_" + key;
}
String portToRegistryStr = getValueFromConfig(protocolConfig, key);
Integer portToRegistry = parsePort(portToRegistryStr);
if (portToRegistry == null) {
portToRegistry = portToBind;
}
// save bind port, used as url's key later
map.put(BIND_PORT_KEY, String.valueOf(portToRegistry));
return portToRegistry;
}
感觉上面的代码,将 map.put(BIND_PORT_KEY, String.valueOf(portToRegistry)); 改成 map.put(BIND_PORT_KEY, String.valueOf(portToBind)); 更合适一点。 绑定端口和注册端口是可以不一样的。这样就和以前一样,能解决@ fl061157 提出的问题了。
fl061157
天立哥,我直接换版本了。2.7.11 。
dubbo3.0.4也有这个问题,只设置了DUBBO_PORT_TO_REGISTRY=20881,但是监听端口也变成了20881,只想让上报到注册中心的端口变
使用了2.7.x新版,这里提供个没有办法的办法:
思路是: ServiceConfig里面有一个扩展点可以用,ConfiguratorFactory这个扩展点执行在port之后,并且可以对URL进行重置,我们实现扩展点,来对port进行重置
ServiceConfig源码如下
String host = findConfigedHosts(protocolConfig, registryURLs, map);
Integer port = findConfigedPorts(protocolConfig, name, map, protocolConfigNum);
URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
// You can customize Configurator to append extra parameters
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.hasExtension(url.getProtocol())) {
url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
}
实现扩展点
public class BindPortFixConfiguratorFactory implements ConfiguratorFactory {
@Override
public Configurator getConfigurator(URL url) {
return new Configurator() {
@Override
public URL getUrl() {
return url;
}
@Override
public URL configure(URL url) {
URL finalURL = checkAndFixRegistryPort(url);
finalURL = checkAndFixBindPort(finalURL);
return finalURL;
}
};
}
private URL checkAndFixRegistryPort(URL url) {
Integer portToRegistryFromEnv = getEnvPortToRegistry();
if(portToRegistryFromEnv != null) {
int portToRegistryFromUrl = url.getPort();
if(portToRegistryFromEnv != portToRegistryFromUrl) {
return url.setPort(portToRegistryFromEnv);
}
}
return url;
}
private URL checkAndFixBindPort(URL url) {
Integer portToBindFromEnv = getEnvPortToBind();
if(portToBindFromEnv != null) {
String bindPort = url.getParameter("bind.port");
if(!portToBindFromEnv.toString().equals(bindPort)) {
return url.addParameter("bind.port", String.valueOf(portToBindFromEnv));
}
}
return url;
}
private Integer getEnvPortToBind() {
String portStr = getValueFromConfig(DUBBO_PORT_TO_BIND);
return parsePort(portStr);
}
private Integer getEnvPortToRegistry() {
String portStr = getValueFromConfig(DUBBO_PORT_TO_REGISTRY);
return parsePort(portStr);
}
private String getValueFromConfig(String key) {
String value = ConfigUtils.getSystemProperty(key);
if (StringUtils.isEmpty(value)) {
value = ConfigUtils.getSystemProperty(key);
}
return value;
}
private Integer parsePort(String configPort) {
Integer port = null;
if (configPort != null && configPort.length() > 0) {
try {
Integer intPort = Integer.parseInt(configPort);
if (isInvalidPort(intPort)) {
throw new IllegalArgumentException("Specified invalid port from env value:" + configPort);
}
port = intPort;
} catch (Exception e) {
throw new IllegalArgumentException("Specified invalid port from env value:" + configPort);
}
}
return port;
}
}`
创建文件spi文件 resources/META-INF/dubbo/xxx.dubbo.spi.BindPortFixConfiguratorFactory
文件内容如下
dubbo=xxx.dubbo.spi.BindPortFixConfiguratorFactory