dubbo 异常Please check registry access list (whitelist/blacklist)的分析与解决

dubbo 异常Please check registry access list (whitelist/blacklist)的分析与解决

工作中遇到了这个异常,当时仅仅是查了解决方法,但问题解决后自己仍存疑惑,所以回家后又在自己的机器上复现了这个异常,并阅读源码解决自己的疑惑。

出现这个问题,抛出的异常如下所示。

com.alibaba.dubbo.rpc.RpcException: Forbid consumer 192.168.1.101 access service service.DemoService from registry 127.0.0.1:2181 use dubbo version 2.8.4, Please check registry access list (whitelist/blacklist).
    at com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:579)
    at com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(AbstractDirectory.java:73)
    at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.list(AbstractClusterInvoker.java:260)
    at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:219)
    at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72)
    at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52)
    at com.alibaba.dubbo.common.bytecode.proxy0.sayHello(proxy0.java)
    at service.Client.main(Client.java:15)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

根据抛出的异常,很容易定位到抛出异常的位置。

com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:579)
  • 1
  • 1

进入到源码579行位置处可以看到抛出该异常是因为forbidden变量被设为true导致。

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).");
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

由于这是消费者一端使用服务导致,下面以最简单的一个消费者代码看看是什么原因forbidden变量被设置为true。

消费端代码如下。

public class Client {
    public static void main(String[] args) throws InterruptedException {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:dubboClient.xml");
        DemoService demoService = (DemoService) ctx.getBean("demoService");
                String ret = demoService.sayHello("Check white list/black list");
                System.out.println(demoService + ":" + ret);
        ctx.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在上述代码ctx.getBean设置断点,一路跟踪可以得到如下的调用栈。

dubbo 异常Please check registry access list (whitelist/blacklist)的分析与解决_第1张图片

这里写图片描述
这里创建了一个监听器,如果孩子结点状态发生变化改方法会被调用。 
而这个调用中toUrlsWithEmpty(url, parentPath, currentChilds)方法中,如果服务提供者列表为空,那么请求协议会被设置为empty。

    private List<URL> toUrlsWithEmpty(URL consumer, String path, List<String> providers) {
        List<URL> urls = toUrlsWithoutEmpty(consumer, providers);
        if (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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

随后上图中notify方法被调用。接着进入notify方法, 
AbstractRegistry:notify(URL url, NotifyListener listener, List urls)会被调用。该方法中第449中调用 listener.notify(categoryList);而这个方法中会调用refreshInvoker(invokerUrls);

这里写图片描述

可以看到当协议为empty,且最终在这个方法中变量被设置为true,导致消费者一方调用方法时抛出check registry access list (whitelist/blacklist)。

而监听器的调用路径可以通过IDE查看得到。那么注册的监听器方法什么时候被触发呢?通过名字可以猜测到,对应的Zookeeper上的结点发生变化时触发。这个可通过在消费端运行时将服务端关闭,对应的Zookeeper上的注册信息删除后,触发对应的Zk结点变更事件该方法被触发,从而导致forbidden变量被设置为true,最后抛出whitelist/blacklist异常。

这里写图片描述

因此解决这个问题这个只需要重新暴露服务,在Zk上注册服务提供者信息即可。具体就是要排查服务提供者可能出现的问题,解决后部署并重启服务提供者即可。

你可能感兴趣的:(dubbo)