dubbo - dubbo2.7.5 dubbo admin "無元數據信息,請升級至Dubbo2.7及以上版本"問題解決


dubbo - dubbo2.7.5   dubbo admin "無元數據信息,請升級至Dubbo2.7及以上版本"問題解決

 

一、問題

  demo使用dubbo 2.7.5版本, dubbo admin 使用develop分支最新版本(引用dubbo 2.7.3),出現以下問題:

 

二、原因

  1. dubbo 2.7以上版本, 增加了元數據, dubbo admin 從2.6升級到2.7會出現上述問題,需要進行以下配置

 

   意思是, 在配置中心中配置元數據地址和內容, 如zookeeper, 在節點/dubbo/config/dubbo/dubbo.properties添加數據 

dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.metadata-report.address=zookeeper://127.0.0.1:2181

  dubbo 相關ISSUE

  

  項目中增加以下代碼處理即可:

  

/**
 * 2.7.0版本及以上 在dubbo-admin顯示元數據的配置,
 *
 * 需要注意, dubbo-admin和服務提供者引入的dubbo為同一版本才行
 *
 * @author TimFruit
 * @date 20-3-3 下午11:49
 */
@EnableDubbo
@Configuration
@Slf4j
public class DubboConfig implements EnvironmentAware {
    private Environment env;
    @Override
    public void setEnvironment(Environment environment) {
        this.env=environment;
    }

    // 2.7.0 版本以上
    // https://blog.csdn.net/wangxq0224/article/details/99304253
    //用於fix dubbo admin : "無元數據信息,請升級至Dubbo2.7及以上版本,或者查看application.properties中關於config center的配置,詳見 這里"
    // https://github.com/apache/dubbo-admin/wiki/Dubbo-Admin%E9%85%8D%E7%BD%AE%E8%AF%B4%E6%98%8E
    @PostConstruct
    public void postInitAdminMeta(){
        final String REGISTRY_ADDRESS="dubbo.registry.address";
        String registryAddress=env.getProperty(REGISTRY_ADDRESS);
        if(!StringUtils.hasText(registryAddress)){
            log.warn(REGISTRY_ADDRESS+"屬性沒有配置值");
            return;
        }
        if(!registryAddress.startsWith("zookeeper")){
            log.info("注冊中心不是zookeeper");
            return;
        }

        //注冊中心為zookeeper, 修復元數據問題

        String data=REGISTRY_ADDRESS+"="+registryAddress;

        final String META_REPORT_ADDRESS="dubbo.metadata-report.address";
        String reportAddress=env.getProperty(META_REPORT_ADDRESS);
        if(StringUtils.hasText(reportAddress)){
            data=data+"\n"+META_REPORT_ADDRESS+"="+reportAddress;
        }

        log.info("\n== data: {}", data);



        //warn: 多個注冊中心未測試
        String connectString=registryAddress.replace("zookeeper://", "");

        RetryPolicy retryPolicy=new RetryNTimes(2, 1000);
        CuratorFramework zkClient=CuratorFrameworkFactory.newClient(connectString,retryPolicy);
        zkClient.start();
        try {
            String nodePath="/dubbo/config/dubbo/dubbo.properties";
            if(zkClient.checkExists().forPath(nodePath)==null){
                zkClient.create()
                        .creatingParentsIfNeeded()
                        .forPath(nodePath, data.getBytes());
            }else {
                zkClient.setData().forPath(nodePath, data.getBytes());
            }


        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            zkClient.close();
        }


    }

 

 

  2. 做了以上配置,仍出現這樣的問題,可以檢查以下dubbo-admin和 服務項目引用的dubbo版本是否相同

  dubbo 2.7.0, dubbo 2.7.3, 以及dubbo 2.7.5 均對元數據相關代碼做了修改,需要使用相同的版本, 才可以查詢相同的元數據路徑

  以下是dubbo 2.7.3 版本, 在zookeeper中的元數據路徑demo,  dubbo 2.7.0版本的元數據路徑后面還有一個節點/service.data

 

 

  3. dubbo admin develop分支, 目前支持的是2.7.3版本, 如果項目使用了dubbo 2.7.5版本, 仍舊會出現該問題, 因為2.7.5版本對元數據處理做了修改

   文末給出本人的解決辦法

 

  4. 在其他配置無誤的情況下, 出現該問題的根本原因是, dubbo admin 和項目dubbo指定的元數據路徑不一致造成的

 

三、dubbo 2.7.5 在dubbo admin 2.7.3 顯示元數據的解決辦法

  1. 增加 "二、原因"中第一點的代碼

  2. 其他關鍵代碼

  2.1) 配置:

# Spring boot application
spring.application.name=dubbo-auto-configuration-provider-demo
# Base packages to scan Dubbo Component: @org.apache.dubbo.config.annotation.Service
dubbo.scan.base-packages=com.ttx.dubbo.simple.provider.service

# Dubbo Application
## The default value of dubbo.application.name is ${spring.application.name}
dubbo.application.name=${spring.application.name}

# Dubbo Protocol
dubbo.protocol.name=dubbo
dubbo.protocol.port=12345



## Dubbo Registry
#dubbo.registry.address=N/A
embedded.zookeeper.port = 2181
## Dubbo Registry
dubbo.registry.address=zookeeper://127.0.0.1:${embedded.zookeeper.port}
dubbo.registry.file = ${user.home}/dubbo-cache/${spring.application.name}/dubbo.cache



## dubbo-admin 元數據
## 使得dubbo2.7.5可在dubbo-admin2.7.3版本的顯示"元數據"的配置, 2.7.3及以下版本無須配置
dubbo.provider.parameters.metadata=myremote
dubbo.metadata-report.sync-report=true


dubbo.metadata-report.address=${dubbo.registry.address}
dubbo.config-center.address=${dubbo.registry.address}


## 使用dubbo2.7.0版本才需要的配置, 可以去掉
spring.main.allow-bean-definition-overriding=true

## 監控
dubbo.monitor.protocol=registry



## DemoService version
dubbo.provider.DemoService.version=1.0.0

 

  2.2)

/**
 * dubbo 2.7.5 在dubbo-admin中顯示元數據的配置
 * @author TimFruit
 * @date 20-3-6 下午10:36
 */
@Configuration
@ConfigurationProperties
@Data
public class DubboConfigProperties {


    /*
    org.apache.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs)
    方法中調用WritableMetadataService metadataService = WritableMetadataService.getExtension(url.getParameter("metadata", "local"));

    默認使用的是local meta服務, 即是存放在內存中

    本屬性自定義meta屬性值, 使用自定義的meta 服務

     */
    //
    public static final String META_REPORT_META="dubbo.provider.parameters.metadata";
//    public static final String META_REPORT_META="dubbo.application.parameters.metadata";

    @Value("${"+META_REPORT_META+":}")
    private String metadata;


}

 

  2.3 ) 增加以下代碼, 使得2.7.5版本可以發送元數據到配置中心

/**
 * dubbo 2.7.5版本存儲meta元數據信息, dubbo-admin 需要使用https://github.com/apache/dubbo-admin  develop開發分支的代碼
 *
 *
 * dubbo 2.7.0版本無須使用該配置, dubbo admin 使用https://github.com/apache/dubbo-admin/archive/0.2.0.tar.gz
 *          https://github.com/apache/dubbo-admin/releases
 *
 * dubbo 2.7.3版本無須使用該配置, dubbo-admin  需要使用https://github.com/apache/dubbo-admin  develop開發分支的代碼, 其引入的dubbo版本為2.7.3
 *
 * @see DubboConfig#postInitAdminMeta() 為顯示2.7.5版本的元數據信息而配置
 *
 * @author TimFruit
 * @date 20-3-6 下午8:04
 */
@Configuration
@Slf4j
public class RemoteWritableMetadataServiceDelegateConfig {

    @Autowired
    DubboConfigProperties dubboConfigProperties;

    @PostConstruct
    public void postMetadataService(){

        String meta=dubboConfigProperties.getMetadata();
        if(!StringUtils.hasText(meta)){
            log.info("沒有使用自定義meta服務...");
            return;
        }

        ExtensionLoader<WritableMetadataService> extensionLoader=ExtensionLoader.getExtensionLoader(WritableMetadataService.class);
        extensionLoader.addExtension(meta, MyRemoteWriteableMetadataService.class);

    }


}

  出現以下日志,表示發送元數據到zookeeper

 

  2.4) 自定義的meta服務

/**
 * @author TimFruit
 * @date 20-3-6 下午10:32
 */
public class MyRemoteWriteableMetadataService extends RemoteWritableMetadataService {
    public MyRemoteWriteableMetadataService() {
        super(
                (InMemoryWritableMetadataService)(ExtensionLoader.getExtensionLoader(WritableMetadataService.class).getExtension("local"))
        );
    }

    @Override
    public void publishServiceDefinition(URL providerUrl) {
        // this.getMetadataReport().storeProviderMetadata(new MetadataIdentifier(providerUrl.getServiceInterface(), providerUrl.getParameter("version"), providerUrl.getParameter("group"), Constants.PROVIDER_SIDE, (String)providerUrl.getParameter("application")), serviceDefinition);
        try {
            String interfaceName = providerUrl.getParameter("interface");
            if (StringUtils.isNotEmpty(interfaceName) && !ProtocolUtils.isGeneric(providerUrl.getParameter("generic"))) {
                Class interfaceClass = Class.forName(interfaceName);
                ServiceDefinition serviceDefinition = ServiceDefinitionBuilder.build(interfaceClass);


                //修改指定路徑參數, 使用2.7.3版本的元數據路徑

                //this.getMetadataReport().storeProviderMetadata(new MetadataIdentifier(providerUrl.getServiceInterface(), providerUrl.getParameter("version"), providerUrl.getParameter("group"), (String)null, (String)null), serviceDefinition);
                this.getMetadataReport().storeProviderMetadata(
                        new MetadataIdentifier(providerUrl.getServiceInterface(),
                                providerUrl.getParameter("version"),
                                providerUrl.getParameter("group"),
                                //以下兩個參數 對應與dubbo admin 項目 org.apache.dubbo.admin.controller.ServiceController#serviceDetail(@PathVariable String service, @PathVariable String env)
                                //方法中的構造參數, 使得提供者和admin都查詢zookeeper相同的元數據路徑
                                Constants.PROVIDER_SIDE,
                                (String)providerUrl.getParameter("application")
                        ), serviceDefinition);



                return;
            }

            this.logger.error("publishProvider interfaceName is empty . providerUrl: " + providerUrl.toFullString());
        } catch (ClassNotFoundException var5) {
            this.logger.error("publishProvider getServiceDescriptor error. providerUrl: " + providerUrl.toFullString(), var5);
        }

        this.publishProvider(providerUrl);

 

  admin顯示元數據成功的結果

 

 

  完整demo代碼

 

 

四、后記

   本人尚未查找到2.7.5版本解決方法資料,所以查看部分源碼暫時解決。 dubbo源碼十分復雜(十幾萬行代碼), 和 spring 有的一拼。 本人尚未理解所有流程,可能會有所紕漏。如果官方或者其他出了更優雅的解決方案, 還請留言告知。

  bug多數是由代碼變更造成的, 願程序猿一生無bug !T_T  (在十幾萬行完全陌生的復雜代碼找bug, 實在太痛苦了 T_T)

 

參考資料:

  dubbo-admin使用新版本和dubbo的2.7版本發現沒有元數據的原因

 


免責聲明!

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



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