Upgrade dubbo default.version

Keywords: Dubbo

Last week, I encountered a compatibility problem about upgrading dubbo 2.6 to 2.7, which almost caused an online failure. Here is a record and a reminder.

Problem playback

The provider of an interface (dubbo 2.6.6) configures the version number of the interface in this way

<dubbo:provider version="1.0.0"/>

The reference configuration of the consumer (also dubbo 2.6.6)

<dubbo:reference id="sampleService" version="1.0.0" check="false" interface="com.newboo.basic.api.SampleService"/>

Then upgrade the consumer's dubbo version, and upgrade the consumer to dubbo 2.7.3 through one-stop operation. During the pre test, it is found that the call message No provider is called. Fortunately, it is found during the test, otherwise the consequences will be unimaginable

No provider available from registry 127.0.0.1:2181

Root cause analysis

View the URL registered to the registry as follows

dubbo://10.0.0.6:20880/com.newboo.basic.api.SampleService?anyhost=true&application=ddog-provider-this-two&bind.ip=10.0.0.6&bind.port=20880&default.version=1.0.0&dubbo=2.0.2&generic=false&interface=com.newboo.basic.api.SampleService&methods=getByUid&owner=roshilikang&pid=82799&qos.accept.foreign.ip=true&qos.enable=true&side=provider&timestamp=1616848403414

You can see that it has no version field and is replaced by the default.version field

Take a look at the matching version logic in Dubbo, which is located in the isMatch method of org.apache.dubbo.common.utils.UrlUtils class, and pick out the key parts

String consumerGroup = consumerUrl.getParameter(GROUP_KEY);
String consumerVersion = consumerUrl.getParameter(VERSION_KEY);
String consumerClassifier = consumerUrl.getParameter(CLASSIFIER_KEY, ANY_VALUE);

String providerGroup = providerUrl.getParameter(GROUP_KEY);
String providerVersion = providerUrl.getParameter(VERSION_KEY);
String providerClassifier = providerUrl.getParameter(CLASSIFIER_KEY, ANY_VALUE);
return (ANY_VALUE.equals(consumerGroup) || StringUtils.isEquals(consumerGroup, providerGroup) || StringUtils.isContains(consumerGroup, providerGroup))
        && (ANY_VALUE.equals(consumerVersion) || StringUtils.isEquals(consumerVersion, providerVersion))
        && (consumerClassifier == null || ANY_VALUE.equals(consumerClassifier) || StringUtils.isEquals(consumerClassifier, providerClassifier));

The logic is very simple, that is, the version field on the provider and consumer URL s must match. The provider has no version field, only the default.version field. Obviously, an error occurs when calling.

But before 2.6.6, there was no problem. Why? After looking at the implementation of 2.6.6, the code is the same, but click providerUrl.getParameter(VERSION_KEY);, It is found that its implementation is not simple

public String getParameter(String key) {
    String value = parameters.get(key);
    if (value == null || value.length() == 0) {
        value = parameters.get(Constants.DEFAULT_KEY_PREFIX + key);
    }
    return value;
}

Take the value corresponding to the key first. If not, add a prefix default. To take it once, that is, only one of version and default.version has a value (version takes precedence).

In contrast, the implementation of 2.7.3 is very straightforward

public String getParameter(String key) {
    return parameters.get(key);
}

Therefore, this directly leads to an error when 2.7.3 calls the default.version interface of 2.6.6. This problem also exists in similar group s, and even some parameters such as timeout may become invalid.

This problem is still obvious. Someone should have encountered it. After searching github, I found the relevant issue

come from: https://github.com/apache/dubbo/issues/5948

This issue has an associated repair. It says that 2.7.7 has fixed this problem, so I tested 2.7.7. Unfortunately, I still reported an error and looked at the repair code

Different from the compatibility of 2.6.6, the repair here is to add compatibility logic to the valueOf method of URL class. The repairer thinks that the URL strings on all registries can finally become URL objects and be used by dubbo through this method.

The idea is right, but through debugging, it is found that not every URL object comes from the valueOf method. In 2.7.7, the parseEncodedStr method of URLStrParser class is used to process the provider's URL during subscription, so this repair is invalid.

About the author: focus on the development of the middleware in the back end, the author of the official account of "bug catching master", pay attention to me, give you the most pure dry cargo technology.

Posted by clarky08 on Sun, 31 Oct 2021 22:22:01 -0700