404008945 commented on issue #10393:
URL: https://github.com/apache/dubbo/issues/10393#issuecomment-1206584496
> @404008945 provider 和 consumer 都升级,2.7 的早期有个版本注册是有问题的
问题找到了。
生产和消费者都是升级了最新版的2.7.16,另外nacos-client为1.3.3时有问题,**测试nacos-client版本为2.0.4已经没有问题了**
**问题记录**
生产者注册服务名称逻辑为
org.apache.dubbo.common.URL#getColonSeparatedKey
```java
public String getColonSeparatedKey() {
StringBuilder serviceNameBuilder = new StringBuilder();
serviceNameBuilder.append(this.getServiceInterface());
append(serviceNameBuilder, VERSION_KEY, false);
append(serviceNameBuilder, GROUP_KEY, false);
return serviceNameBuilder.toString();
}
```
当version为空时并不会省略掉间隔符冒号
于是注册的服务名称是
io.seata.samples.tcc.dubbo.action.TccActionOne::tcc

然后我又看了消费者启动时初始化invoke时,生成的订阅服务名称逻辑
org.apache.dubbo.registry.nacos.NacosRegistry#getServiceNames0
```java
private Set<String> getServiceNames0(URL url) {
NacosServiceName serviceName = createServiceName(url);
final Set<String> serviceNames;
if (serviceName.isConcrete()) { // is the concrete service name
serviceNames = new LinkedHashSet<>();
serviceNames.add(serviceName.toString());
// Add the legacy service name since 2.7.6
String legacySubscribedServiceName =
getLegacySubscribedServiceName(url);
if (!serviceName.toString().equals(legacySubscribedServiceName))
{
//avoid duplicated service names
serviceNames.add(legacySubscribedServiceName);
}
} else {
serviceNames = filterServiceNames(serviceName);
}
return serviceNames;
}
```

version为空,新版服务名version为空,不会省略间隔符冒号,根据注释,为了兼容2.7.3以前的版本,另外生成服务名
version为空并且把冒号也省略掉了。最终结果就是新版比旧版多了一个冒号。
后面会继续分别订阅这两个服务名称,其中一个服务名在注册中心不存在,是空服务。
org.apache.dubbo.registry.nacos.NacosRegistry#doSubscribe(org.apache.dubbo.common.URL,
org.apache.dubbo.registry.NotifyListener, java.util.Set<java.lang.String>)
```java
private void doSubscribe(final URL url, final NotifyListener listener,
final Set<String> serviceNames) {
execute(namingService -> {
if (isServiceNamesWithCompatibleMode(url)) {
List<Instance> allCorrespondingInstanceList =
Lists.newArrayList();
/**
* Get all instances with serviceNames to avoid instance
overwrite and but with empty instance mentioned
* in https://github.com/apache/dubbo/issues/5885 and
https://github.com/apache/dubbo/issues/5899
*
* namingService.getAllInstances with {@link
org.apache.dubbo.registry.support.AbstractRegistry#registryUrl}
* default {@link DEFAULT_GROUP}
*
* in https://github.com/apache/dubbo/issues/5978
*/
for (String serviceName : serviceNames) {
List<Instance> instances =
namingService.getAllInstances(serviceName,
getUrl().getParameter(GROUP_KEY,
Constants.DEFAULT_GROUP));
NacosInstanceManageUtil.initOrRefreshServiceInstanceList(serviceName,
instances);
allCorrespondingInstanceList.addAll(instances);
}
notifySubscriber(url, listener,
allCorrespondingInstanceList);
for (String serviceName : serviceNames) {
subscribeEventListener(serviceName, url, listener);
}
} else {
List<Instance> instances = new LinkedList<>();
for (String serviceName : serviceNames) {
instances.addAll(namingService.getAllInstances(serviceName
, getUrl().getParameter(GROUP_KEY,
Constants.DEFAULT_GROUP)));
notifySubscriber(url, listener, instances);
subscribeEventListener(serviceName, url, listener);
}
}
});
}
```
上面有段很好的注释 ,**Get all instances with serviceNames to avoid instance overwrite
and but with empty instance mentioned**获取所有的serviceNames
的实例,防止被空的实例覆盖。看起来好像没有问题。
但是下面的循环serviceNames订阅
```java
for (String serviceName : serviceNames) {
subscribeEventListener(serviceName, url, listener);
}
```
但是注册中心为nacos时
这里来到了nacos客户端 版本为1.3.3时
```java
public void addListener(ServiceInfo serviceInfo, String clusters,
EventListener listener) {
NAMING_LOGGER.info("[LISTENER] adding " + serviceInfo.getName() + "
with " + clusters + " to listener map");
List<EventListener> observers = Collections.synchronizedList(new
ArrayList<EventListener>());
observers.add(listener);
observers =
observerMap.putIfAbsent(ServiceInfo.getKey(serviceInfo.getName(), clusters),
observers);
if (observers != null) {
observers.add(listener);
}
serviceChanged(serviceInfo);
}
```
会发现在第一次添加监听器时还是会触发serviceChange,进而触发notify,重新刷新invoker,由于实例为空的服务名也被订阅,那么这时候还是可能会发生被空的实例覆盖的情况。
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]