dubbo icon indicating copy to clipboard operation
dubbo copied to clipboard

No provider available issue

Open xuyuTT opened this issue 1 year ago • 12 comments

When initiated together by consumers and providers

private void doSubscribe(final URL url, final NotifyListener listener, final Set<String> serviceNames) {
        execute(namingService -> {
            if (isServiceNamesWithCompatibleMode(url)) {
                List<Instance> allCorrespondingInstanceList = new ArrayList<>();

                /**
                 * 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);
                }
            }

        });
    }

after consumer run

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);

the field forbidden in DynamicDirectory become true, at this time, provider register to nacos, and then consumer run

for (String serviceName : serviceNames) {
                    subscribeEventListener(serviceName, url, listener);
                }

so it seems that consumer miss nacos notify because provider registed before consumer subscribe it on nacos. cause forbidden is always true.
这段代码之间,生产者注册到了nacos,此时,由于消费者还没向nacos监听服务,所以收不到通知,导致这个情况下forbidden属性不通过外力干涉,一直是true,导致调用no provider,我通过debug能复现此问题,不确定我的分析是否合理?

xuyuTT avatar Jan 18 '24 08:01 xuyuTT

Please translate this issue into English :)

AlbumenJ avatar Jan 18 '24 12:01 AlbumenJ

Do you mean that you export and refer the same service in the same process?

AlbumenJ avatar Jan 18 '24 12:01 AlbumenJ

When initiated together by consumers and providers,after consumer run

notifySubscriber(url, listener, allCorrespondingInstanceList);

provider registed with nacos, and then consumer run

for (String serviceName : serviceNames) {
      subscribeEventListener(serviceName, url, listener);
 }

so it seems like consumer miss nacos notify because provider registed before consumer subscribe.

xuyuTT avatar Jan 19 '24 02:01 xuyuTT

当provider的注册时机是发生在consumer拉取和订阅注册中心之间时,consumer会获取不到provider的信息. consumer先订阅,在拉取似乎能解决这个问题.

When the provider's registration timing occurs between the consumer pulling and subscribing to the registration center, the consumer will not be able to obtain the provider's information. The consumer subscribes first and pulls later, which seems to solve this problem.

laywin avatar Jan 24 '24 12:01 laywin

pls assign to me. @AlbumenJ

laywin avatar Mar 14 '24 14:03 laywin

I think this has been fixed in the latest 3.2.x version.

AlbumenJ avatar Mar 15 '24 09:03 AlbumenJ

In org/apache/dubbo/config/deploy/DefaultModuleDeployer.java:183

AlbumenJ avatar Mar 15 '24 09:03 AlbumenJ

In org/apache/dubbo/config/deploy/DefaultModuleDeployer.java:183

i think there is also exist the problem, the case is come from.

                for (String serviceName : serviceNames) {
                    List<Instance> instances =
                            namingService.getAllInstances(serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP));
                    notifySubscriber(url, serviceName, listener, instances);
                }
                for (String serviceName : serviceNames) {
                    subscribeEventListener(serviceName, url, listener);
                }

namingService.getAllInstances(serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP));

When there is no provider, The final effect of this code is to obtain the instance and subscribe. the subscription at this time has side effects. The reason is that the listener is not registered.

Before the listener is registered, if the service provider registration message is received, Then the message will be lost.

laywin avatar Mar 17 '24 14:03 laywin

In org/apache/dubbo/config/deploy/DefaultModuleDeployer.java:183

i think there is also exist the problem, the case is come from.

                for (String serviceName : serviceNames) {
                    List<Instance> instances =
                            namingService.getAllInstances(serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP));
                    notifySubscriber(url, serviceName, listener, instances);
                }
                for (String serviceName : serviceNames) {
                    subscribeEventListener(serviceName, url, listener);
                }

namingService.getAllInstances(serviceName, getUrl().getGroup(Constants.DEFAULT_GROUP));

When there is no provider, The final effect of this code is to obtain the instance and subscribe. the subscription at this time has side effects. The reason is that the listener is not registered.

Before the listener is registered, if the service provider registration message is received, Then the message will be lost.

The reason is that the listener is not registered. Why?

AlbumenJ avatar Mar 18 '24 02:03 AlbumenJ

listener registered happens in subscribeEventListener method. so when service provider registration message is received happens between notifySubscriber() and subscribeEventListener(), the message will be lost.

laywin avatar Mar 18 '24 10:03 laywin

subscribeEventListener(serviceName, url, listener)

image This is not depend on whether there have providers or not.

AlbumenJ avatar Mar 19 '24 01:03 AlbumenJ

subscribeEventListener(serviceName, url, listener)

image This is not depend on whether there have providers or not.

I think the code we are discussing should be in getAllInstances and subscribeEventListener. getAllInstances will have subscription operations when there is no provider , but at this time there not exist a listener.

laywin avatar Mar 19 '24 02:03 laywin