ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Dubbo常见错误分析

2022-02-08 17:33:46  阅读:143  来源: 互联网

标签:Dubbo 错误 ... URL 常见 List url provider consumer


目录

dubbo版本

  1. dubbo版本2.6.7

No provider available from registry

  1. 如果没有服务提供者,消费者会抛出异常

    No provider available from registry dubbo-zookeeper:2181 for service group0/cn.jannal.dubbo.facade.DemoService:1.0.0 on consumer 172.16.117.33 use dubbo version 2.6.7, please check status of providers(disabled, not registered or in blacklist).
    
  2. 上面的异常是在RegistryDirectory#doList方法中抛出。可以看到当forbidden=true才抛出异常

    public List<Invoker<T>> doList(Invocation invocation) {
        // 服务提供者关闭或禁用了服务,此时抛出 No provider 异常
        if (forbidden) {
            // 1. No service provider 2. Service providers are disabled
            throw new RpcException(RpcException.FORBIDDEN_EXCEPTION,
                    "No provider available from registry " + getUrl().getAddress() + " for service " + getConsumerUrl().getServiceKey() + " on consumer " + NetUtils.getLocalHost()
                            + " use dubbo version " + Version.getVersion() + ", please check status of providers(disabled, not registered or in blacklist).");
        }
    		...省略...
    }  
    
  3. forbidden设置为true是在RegistryDirectory#refreshInvoker设置的。refreshInvoker是在RegistryDirectory#notify中被调用。 当某个服务的provider有变化时RegistryDirectory#notify就会被调用(例如zookeeper上某个服务的provider目录里的内容发生变化,则zk监听器会被触发)

    // URL的protocol是如何变为empty的?
    private void refreshInvoker(List<URL> invokerUrls) {
      if (invokerUrls != null && invokerUrls.size() == 1 && invokerUrls.get(0) != null
              && Constants.EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {
          this.forbidden = true; // Forbid to access
          this.methodInvokerMap = null; // Set the method invoker map to null
          destroyAllInvokers(); // Close all invokers
      } 
      ...省略...
    }
    
     @Override
    public synchronized void notify(List<URL> urls) {
      List<URL> invokerUrls = new ArrayList<URL>();
      List<URL> routerUrls = new ArrayList<URL>();
      List<URL> configuratorUrls = new ArrayList<URL>();
      for (URL url : urls) {
          String protocol = url.getProtocol();
          String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
          if (Constants.ROUTERS_CATEGORY.equals(category)
                  || Constants.ROUTE_PROTOCOL.equals(protocol)) {
              routerUrls.add(url);
          } else if (Constants.CONFIGURATORS_CATEGORY.equals(category)
                  || Constants.OVERRIDE_PROTOCOL.equals(protocol)) {
              configuratorUrls.add(url);
          } else if (Constants.PROVIDERS_CATEGORY.equals(category)) {
              invokerUrls.add(url);
          } else {
              logger.warn("Unsupported category " + category + " in notified url: " + url + " from registry " + getUrl().getAddress() + " to consumer " + NetUtils.getLocalHost());
          }
      }
      ...省略...
      // providers
      refreshInvoker(invokerUrls);
    }
    
  4. 查看notify URL发现URL中的协议是empty。那URL的protocol是如何变为empty的?

    image-20211227113008964

  5. 查看ZookeeperRegistry#doSubscribe,zookeeper初次订阅或者订阅的信息有变更时,都会触发ChildListener的childChanged方法,此方法调用前会调用toUrlsWithEmpty方法进行empty协议的设置。即如果consumer的URL与所有provider都不匹配,则将consumer的protocol设置为empty协议,从而最终导致forbidden=true

    protected void doSubscribe(final URL url, final NotifyListener listener){
      
      ...省略...
      ChildListener zkListener = listeners.get(listener);
      if (zkListener == null) {
          listeners.putIfAbsent(listener, new ChildListener() {
              @Override
              public void childChanged(String parentPath, List<String> currentChilds) {
                  ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds));
              }
          });
          zkListener = listeners.get(listener);
      }
      ...省略...
    }
    
    
    private List<URL> toUrlsWithEmpty(URL consumer, String path, List<String> providers) {
        List<URL> urls = toUrlsWithoutEmpty(consumer, providers);
      	//如果consumer的URL与所有provider都不匹配,则将consumer的protocol设置为empty协议
        if (urls == null || urls.isEmpty()) {
            int i = path.lastIndexOf('/');
            String category = i < 0 ? path : path.substring(i + 1);
            URL empty = consumer.setProtocol(Constants.EMPTY_PROTOCOL).addParameter(Constants.CATEGORY_KEY, category);
            urls.add(empty);
        }
        return urls;
    }
    
    private List<URL> toUrlsWithoutEmpty(URL consumer, List<String> providers) {
        List<URL> urls = new ArrayList<URL>();
        if (providers != null && !providers.isEmpty()) {
          	//遍历所有provider
            for (String provider : providers) {
                provider = URL.decode(provider);
                if (provider.contains("://")) {
                    URL url = URL.valueOf(provider);
                  	//如果与consumer的URL匹配,则添加url列表中
                    if (UrlUtils.isMatch(consumer, url)) {
                        urls.add(url);
                    }
                }
            }
        }
        return urls;
    }
    

标签:Dubbo,错误,...,URL,常见,List,url,provider,consumer
来源: https://www.cnblogs.com/jannal/p/15872048.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有