zoukankan      html  css  js  c++  java
  • Dobbo问题及解决方案:forbid-consumer

    本地运行Dubbo经常出现以下情况:

    com.alibaba.dubbo.rpc.RpcException: Forbid consumer 10.0.53.69 access service com.kuaidadi.op.api.pay.service.PayChannelConfigRemoteService from registry 10.0.50.150:2181 use dubbo version 2.5.3, Please check registry access list (whitelist/blacklist).

    一、问题分析:

    其实线下环境根本没有对服务做白名单和黑名单机制。通过阅读源码,分析如下:

    根据异常栈,抛出这个异常的代码在RegistryDirectory的第579行,如下:

    public List<Invoker<T>> doList(Invocation invocation) {
     if (forbidden ) {
         throw new RpcException(RpcException.FORBIDDEN_EXCEPTION , ” Forbid consumer “ +  NetUtils. getLocalHost() + ” access service “ +        getInterface().getName() + ” from registry “ + getUrl().getAddress() + ” use dubbo version “ + Version.getVersion() + “, Please check registry access list (whitelist/blacklist).”);
    }

    如果forbidden变量为true,则抛出该异常。forbidden变量默认为false,那么什么时候变成true了呢?看RegistryDirectory的这段代码:

    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; // 禁止访问
                this.methodInvokerMap = null; // 置空列表
                destroyAllInvokers(); // 关闭所有Invoker
       }

    意思是如果invokerUrls的size为1,并且url的协议头是Constants.EMPTY_PROTOCOL时,则设置forbidden为false,Constants.EMPTY_PROTOCOL的值是empty。

    refreshInvoker方法什么时候被调用呢?当某个服务的provider有变化时就会被调用,例如zookeeper上某个服务的provider目录里的内容发生变化,则zk监听器会被触发,由于provider的数量会发生变化,所以必须刷新本地的对provider的连接,具体逻辑就在refreshInvoker方法里。

    可以确定的是,zookeeper推送的URL的protocol部分不可能无缘无故变成了empty,肯定是由某个地方更改了,于是看一下Constants.EMPTY_PROTOCOL到底有哪些地方调用了。当zookeeper初次订阅或者订阅的信息有变更时,都会触发toUrlsChanged方法,看看这个方法内部都做了什么,完整代码如下:

     private List<URL> toUrlsWithEmpty(URL consumer, String path, List<String> providers) {
            List<URL> urls = toUrlsWithoutEmpty(consumer, providers);
            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;
        }

    二、总结

    可见如果toUrlsWithoutEmpty的结果是空或者size为0,则强制返回一个protocol为empty的url,看来源头就在这里了。传入的List<String> providers实际上就是最新的服务提供者信息,当某个服务没有任何provider时,providers就变为一个size为0的List了,导致返回一个协议头为empty的url,进而导致forbidden为true,屏蔽了consumer调用。

  • 相关阅读:
    一种不求交点确定直线与三角形是否相交的方法
    碰撞边界锯齿的平滑方法
    demo的凹凸贴图效果
    MySQL进阶篇触发器
    MySQL进阶篇索引
    Maven的POM文件详解
    Swagger
    MySQL进阶篇存储过程
    SpringBoot基础篇
    MySQL基础篇多表操作
  • 原文地址:https://www.cnblogs.com/eyesmoon/p/10064486.html
Copyright © 2011-2022 走看看