background

This article describes a recent reader’s feedback about application-level service discovery in Dubbo 2.7.x. The introduction to application-level service discovery in Dubbo can be found in the previous article “First Experience of Application-level Service Discovery in Dubbo”, which is not covered here.

Readers reported that they were developing dubbo gateway based on Dubbo 2.7 application level service discovery. According to the article “Dubbo Application level service Discovery Experience”, they wrote the error of no Provider when calling demo.

First of all, I think they have a good idea. Not many companies have put Dubbo app discovery into production. Secondly, there was no problem in the test when writing the article, but in order to help readers solve the problem, I still wrote a new demo test.

Problem orientation

I took a dubbo demo project (not dubbo demo in dubbo source code) and found that zooKeeper could not be registered. Then I tested different versions and found that zooKeeper could not be registered. No error was reported in versions 2.7.5 ~ 2.7.11. The following NPE error is reported in version 2.7.12

The 2021-06-16 13:17:31, 086 [Dubbo - framework - the scheduler - thread - 1] ERROR org. Apache. Dubbo. Config. The bootstrap. DubboBootstrap (dubbobootstrap.java :1172) - [DUBBO] refresh Metadata and instance failed, DUBBO version: 2.7.12, current host: 172.23.233.52 Java. Lang. NullPointerException ats org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.calInstanceRevision(ServiceInstanceMetadataUtils. java:249) at org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.lambda$refreshMetadataAndInstance$6(ServiceInstan ceMetadataUtils.java:272) at java.util.ArrayList.forEach(ArrayList.java:1259) at org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.refreshMetadataAndInstance(ServiceInstanceMetadat aUtils.java:271) at org.apache.dubbo.config.bootstrap.DubboBootstrap.lambda$registerServiceInstance$20(DubboBootstrap.java:1170) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at  java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)Copy the code

It is speculated that there is a problem with the service registration. With this error stack debug, the problem is quickly located

As a direct result of NPE is located in the org. Apache. Dubbo. Registry. Client. AbstractServiceDiscovery# register

In version <=2.7.11

@Override
public final void register(ServiceInstance serviceInstance) throws RuntimeException {
    this.serviceInstance = serviceInstance;
    doRegister(serviceInstance);
}
Copy the code

In version 2.7.12, the code order was changed to

@Override
public final void register(ServiceInstance serviceInstance) throws RuntimeException {
	  doRegister(serviceInstance);
    this.serviceInstance = serviceInstance;
}
Copy the code

Why did reordering the code result in an error?

This. ServiceInstance is null. The original code assigns a value to this NPE and then executes doRegister. The adjusted code executes doRegister and then assigns. However, an exception is thrown when diRegister is executed. Unfortunately, the exception is eaten

@Override
public final void register(ServiceInstance serviceInstance) throws RuntimeException {

    assertDestroyed(REGISTER_ACTION);
    assertInitialized(REGISTER_ACTION);

    executeWithEvents(
            of(new ServiceInstancePreRegisteredEvent(serviceDiscovery, serviceInstance)),
            () -> serviceDiscovery.register(serviceInstance),
            of(new ServiceInstanceRegisteredEvent(serviceDiscovery, serviceInstance))
    );
}
Copy the code

This executeWithEvents will issue the exception as an event

protected final void executeWithEvents(Optional
        beforeEvent, ThrowableAction action, Optional
        afterEvent) {
    beforeEvent.ifPresent(this::dispatchEvent);
    try {
        action.execute();
    } catch (Throwable e) {
        dispatchEvent(new ServiceDiscoveryExceptionEvent(this, serviceDiscovery, e));
    }
    afterEvent.ifPresent(this::dispatchEvent);
}
Copy the code

However, the event is not processed after it is thrown, which means that the exception is eaten. This is why the previous version of Dubbo did not throw an exception and could not register the service.

What is this exception?

java.lang.NoClassDefFoundError: org/apache/curator/x/discovery/ServiceDiscovery
Copy the code

It just introduces one less dependency. Add the following to solve this problem

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-registry-zookeeper</artifactId>
    <version>${version}</version>
</dependency>
Copy the code

Why didn’t I encounter this problem when I wrote the article?

Just this debugging is based on a demo project, “Dubbo application level service discovery experience” article is directly in the Dubbo source code to modify the demo, the source code has introduced the dependency

further

It’s actually a small problem, but confusing to users. Why can’t you register for the service without reporting an error? It would have been more difficult if there had not been an error in 2.7.12.

Therefore, I proposed an issue and communicated with friends in the community, and came to the conclusion that the app-level service discovery of 2.7.x would no longer be maintained, and 3.x would continue to be maintained.

Github.com/apache/dubb…

Raising an issue is also to let users with problems can search, avoid detours.

By the way, I also mentioned PR, plus a line of log, so it’s easy to find this problem intuitively.

Github.com/apache/dubb…

The new version (>=2.7.13) will print an error like this if a friend encounters this problem again

The 2021-06-16 16:58:02, 210 [main] ERROR org. Apache. Dubbo. Registry. Client. EventPublishingServiceDiscovery (EventPublishingServiceDiscovery.java:287) - [DUBBO] Execute action throws and dispatch a ServiceDiscoveryExceptionEvent, dubbo version: 2.7.12, current host: 172.23.233.52 Java. Lang. BootstrapMethodError: java.lang.NoClassDefFoundError: org/apache/curator/x/discovery/ServiceDiscovery at org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery.doRegister(ZookeeperServiceDiscovery.java:92) at org.apache.dubbo.registry.client.AbstractServiceDiscovery.register(AbstractServiceDiscovery.java:33) at org.apache.dubbo.registry.client.EventPublishingServiceDiscovery.lambda$register$0(EventPublishingServiceDiscovery.java: 159) at org.apache.dubbo.registry.client.EventPublishingServiceDiscovery.executeWithEvents(EventPublishingServiceDiscovery.java: 285) at org.apache.dubbo.registry.client.EventPublishingServiceDiscovery.register(EventPublishingServiceDiscovery.java:157) at org.apache.dubbo.config.bootstrap.DubboBootstrap.lambda$doRegisterServiceInstance$21(DubboBootstrap.java:1192) at java.util.ArrayList.forEach(ArrayList.java:1259) ...Copy the code

Since 2.7.x application level service discovery is not updated, next time write an article analyzing the application level service discovery source code for version 3.0


Search attention wechat public number “bug catching master”, back-end technology sharing, architecture design, performance optimization, source code reading, problem solving, practice.