解决dubbo问题:forbid consumer

线下环境经常出现类似这种异常:

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).
大致意思是当前调用者被禁止访问某个服务,请检查下注册中心访问列表,还有黑名单和白名单。
其实线下环境根本没有对服务做白名单和黑名单机制,因为线下环境给开发人员的账号是guest,没有权限做黑白名单。今天有好几个人问我这个问题,我仔细看了源码,找出了根源所在。
根据异常栈,抛出这个异常的代码在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启动了,有一个provider下线了,所以必须刷新本地的对provider的连接,具体逻辑就在refreshInvoker方法里,这个方法的调用栈如下:
image_1
可以确定的是,zookeeper推送的URL的protocol部分不可能无缘无故变成了empty,肯定是由某个地方更改了,于是看一下 Constants. EMPTY_PROTOCOL到底有哪些地方调用了,如下:
image_2
见图中红色圈圈部分,当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为o的List了,导致返回一个协议头为empty的url,进而导致forbidden为true,屏蔽了consumer调用。
转载:http://www.jameswxx.com/中间件/解决dubbo问题:forbid-consumer/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值