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×tamp=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.