0


dubbo-无法找到提供者问题(一)

今天启动dubbo,提供者没问题,消费者报错,提示 没有可用的提供者

然后具体跟了以下dubbo代码:

根据报错的位置是在
org.apache.dubbo.config.ReferenceConfig#checkInvokerAvailable

  1. private void checkInvokerAvailable() throws IllegalStateException {
  2. if (shouldCheck() && !invoker.isAvailable()) {//shouldCheck() 默认是开启检查的,invoker.isAvailable()判断是否可用
  3. invoker.destroy();
  4. throw new IllegalStateException("Failed to check the status of the service "
  5. + interfaceName
  6. + ". No provider available for the service "
  7. + (group == null ? "" : group + "/")
  8. + interfaceName +
  9. (version == null ? "" : ":" + version)
  10. + " from the url "
  11. + invoker.getUrl()
  12. + " to the consumer "
  13. + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
  14. }
  15. }

问题应该是就出在了 invoker.isAvailable()中,其中invoker是由

invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));

产生的,所有应该是DubboInvoker,我们看下DubboInvoker

  1. @Override
  2. public boolean isAvailable() {
  3. if (!super.isAvailable()) {
  4. return false;
  5. }
  6. for (ExchangeClient client : clients) {
  7. if (client.isConnected() && !client.hasAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY)) {
  8. //cannot write == not Available ?
  9. return true;
  10. }
  11. }
  12. return false;
  13. }

根据断点提示 client.isConnected() 等于 false,说明此处client是不可用的,继续进去client.isConnected()的方法
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeClient#isConnected

  1. @Override
  2. public boolean isConnected() {
  3. return channel.isConnected();
  4. }

org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#isConnected

  1. @Override
  2. public boolean isConnected() {
  3. return channel.isConnected();
  4. }

此处我们看下channel的对接端信息
在这里插入图片描述
这就奇怪了,原本我是单机起的两个服务进行调用,为啥ip不一致呢,目前通过 ifconfig 查询 我本机ip应该是 192.168.124.2,即消费端ip是正确的,提供端ip错误了。

然后我们定位下 服务端的 ip 获取方式,因为RegistryProtocol是开始zk注册的入口,我们直接看下 org.apache.dubbo.registry.integration.RegistryProtocol#export

  1. @Override
  2. public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
  3. URL registryUrl = getRegistryUrl(originInvoker);
  4. //此方法用于组织提供端的服务信息,所以我们断点看下providerUrl信息
  5. URL providerUrl = getProviderUrl(originInvoker);
  6. 。。。
  7. }

在这里插入图片描述
由图可以看到 此处已经获取到了一个错误的ip

我们继续看下如何获取的这个错误ip

  1. private URL getProviderUrl(final Invoker<?> originInvoker) {
  2. //String EXPORT_KEY = "export"
  3. Object providerURL = originInvoker.getUrl().getAttribute(EXPORT_KEY);
  4. if (!(providerURL instanceof URL)) {
  5. throw new IllegalArgumentException("The registry export url is null! registry: " + originInvoker.getUrl().getAddress());
  6. }
  7. return (URL)providerURL;
  8. }

由此处我们得知 ip是url中存储的,对于存储 我们知道在 ServiceConfig的doExportUrlsFor1Protocol方法中会存储map信息到url中

  1. private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
  2. 、、、
  3. //获取host
  4. String host = findConfigedHosts(protocolConfig, registryURLs, map);
  5. Integer port = findConfigedPorts(protocolConfig, name, map);
  6. URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);
  7. 、、、
  8. Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass,
  9. //EXPORT_KEY = "export",将url保存进url中
  10. registryURL.putAttribute(EXPORT_KEY, url));
  11. }

我们马上就接近真像了,继续看下findConfigedHosts方法

  1. private String findConfigedHosts(ProtocolConfig protocolConfig,
  2. List<URL> registryURLs,
  3. Map<String, String> map) {
  4. 、、、
  5. logger.info("No valid ip found from environment, try to find valid host from DNS.");
  6. hostToBind = InetAddress.getLocalHost().getHostAddress();
  7. 、、、
  8. }

然后我们执行下 InetAddress.getLocalHost().getHostAddress() 发现 确实是 错误的ip:192.168.1.3

为什么呢?
此处我们找到了问题的根源,当前我们的mac环境的hostname是篡改为了虚拟的,

wangwenyong@wangwenyong ~ % hostname
bogon

具体查看文章中解释及修复方式: 点击此链接

既然我们看到了这里,索性 看下 消费端的获取方式是什么:

我们可以从org.apache.dubbo.registry.integration.RegistryProtocol#refer入手,既然订阅 肯定要有自己的ip

  1. public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
  2. 、、、
  3. //REFER_KEY = "refer"
  4. Map<String, String> qs = (Map<String, String>)url.getAttribute(REFER_KEY);
  5. 、、、
  6. return doRefer(cluster, registry, type, url, qs);
  7. }
  8. protected <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url, Map<String, String> parameters) {
  9. //REGISTER_IP_KEY = "register.ip"
  10. URL consumerUrl = new URL(parameters.get(PROTOCOL_KEY) == null ? DUBBO : parameters.get(PROTOCOL_KEY), parameters.get(REGISTER_IP_KEY), 0, getPath(parameters, type), parameters);
  11. url = url.putAttribute(CONSUMER_URL_KEY, consumerUrl);
  12. ClusterInvoker<T> migrationInvoker = getMigrationInvoker(this, cluster, registry, type, url, consumerUrl);
  13. return interceptInvoker(migrationInvoker, url, consumerUrl, url);
  14. }

在这里插入图片描述
我们看下 url中的refer中的register.ip的存储时机的代码,毫无疑问 在org.apache.dubbo.config.ReferenceConfig中
我们直接搜索 REGISTER_IP_KEY便可定位到 在org.apache.dubbo.config.ReferenceConfig#init中

  1. public synchronized void init() {
  2. 、、、
  3. String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);
  4. if (StringUtils.isEmpty(hostToRegistry)) {
  5. //此处为获取ip
  6. hostToRegistry = NetUtils.getLocalHost();
  7. } else if (isInvalidLocalHost(hostToRegistry)) {
  8. throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
  9. }
  10. map.put(REGISTER_IP_KEY, hostToRegistry);
  11. 、、、
  12. }

所以我们得出结论 在消费端 使用的 NetUtils.getLocalHost() 来获取,提供端用的 InetAddress.getLocalHost().getHostAddress()导致的ip不一致,又因为 计算机名错误 获取ip错误

问题的发现多谢了 http://blog.chinaunix.net/uid-540802-id-138782.html 文章的指点


本文转载自: https://blog.csdn.net/m0_54850825/article/details/126327874
版权归原作者 m0_54850825 所有, 如有侵权,请联系我们删除。

“dubbo-无法找到提供者问题(一)”的评论:

还没有评论