zoukankan      html  css  js  c++  java
  • dubbo

    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+"
    "+META_REPORT_ADDRESS+"="+reportAddress;
            }
    
            log.info("
    == 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版本发现没有元数据的原因

    人生没有彩排,每一天都是现场直播
  • 相关阅读:
    JavaScript在Javascript中为String对象添加trim,ltrim,rtrim方法
    JavaScriptjs写的俄罗斯方块
    WinForm中“嵌入的资源”和“资源文件”数据的获取方式
    Facade模式(外观模式)
    windows服务安装程序中如何安装后自动启动
    水晶报表之主从多表数据源批量预览及打印开发设计
    IP地址分类简介
    水晶报表之各节的作用
    水晶报表开发之常用代码以及注意事项
    .Net中后台线程和前台线程的区别
  • 原文地址:https://www.cnblogs.com/timfruit/p/12433931.html
Copyright © 2011-2022 走看看