升級 dubbo 小心 default.version


上周遇到個關於升級dubbo 2.6 到2.7的兼容性問題,差點造成線上故障,這里記錄下,也給大家提個醒。

問題回放

有一個接口的提供方(dubbo 2.6.6)這么配置接口的版本號

<dubbo:provider version="1.0.0"/>

消費方(也是dubbo 2.6.6)的reference這么配置

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

然后升級消費方的dubbo版本,經過一通操作將消費者升級到dubbo 2.7.3,預發測試時發現調用報No provider,還好是在測試時發現,不然后果不堪設想

No provider available from registry 127.0.0.1:2181

根因分析

查看注冊到注冊中心的URL是這樣

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

可以看到它沒有version字段,取而代之的是default.version字段

看一下dubbo中匹配version這個邏輯,位置在org.apache.dubbo.common.utils.UrlUtils類的isMatch方法,摘出重點部分

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

邏輯很簡單,就是provider和consumer URL上的version字段得匹配上,提供者沒有version字段,只有default.version字段,很顯然調用時報錯。

但之前2.6.6是沒有問題的,為什么?看了下2.6.6的實現,代碼也是一樣,但點進providerUrl.getParameter(VERSION_KEY);,發現它的實現不簡單

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

先取key對應的值,取不到時,再加個前綴default.取一次,也就是說versiondefault.version兩者只要有一個有值即可(version優先)。

反觀2.7.3的實現就非常耿直

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

所以,這就直接導致了2.7.3調用2.6.6的default.version接口報錯,類似的group也存在這個問題,甚至還有一些如timeout等參數都可能會失效。

這個問題還是比較明顯,應該有人遇到,搜索了一下github,果然讓我找到了相關的issue

image

來自:https://github.com/apache/dubbo/issues/5948

這個issue有一個相關聯的修復,說是2.7.7已經修復了這個問題,於是我測試了一下2.7.7,很遺憾,還是報錯,看了下修復代碼

image

和2.6.6的兼容不一樣,這里修復是在 URL 類的 valueOf 方法中添加兼容邏輯,修復者想的是所有注冊中心上的URL字符串最終得經過這個方法才能成為URL對象,才能為dubbo所用。

想法是沒錯,但通過調試發現並不是每個URL對象都來自valueOf方法,2.7.7中訂閱時對提供者的URL進行處理的是URLStrParser類的parseEncodedStr方法,所以這個修復就是無效的了。


關於作者:專注后端的中間件開發,公眾號"捉蟲大師"作者,關注我,給你最純粹的技術干貨

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM