sofastack / sofa-rpc-node

SOFARPC Node is a high-performance, high-extensibility, production-level Nodejs RPC framework.
MIT License
614 stars 64 forks source link

集成 dubbo 时,直连服务是可以的,但是通过注册中心就不成功了 #15

Closed JimmyDaddy closed 6 years ago

JimmyDaddy commented 6 years ago
* 上述原因导致 invoke 时 执行

async getConnection(req) { return await this._addressGroup.getConnection(req); }


时返回 null

想知道为什么  addressList 是空的?

集成 dubbo 时,直连服务是可以的,但是通过注册中心就不成功了

还有 group 的设置貌似不成功,直连的时候我需要将 group 名字写在 interfaceName 里面才行,单独配置 group 或者在初始化 client 时设置 group 都不成功
gxcsoccer commented 6 years ago

https://github.com/alipay/sofa-rpc-node/pull/17

gxcsoccer commented 6 years ago

服务端代码用的是官方的 demo,然后将 registry 配置成 zookeeper

https://github.com/apache/incubator-dubbo/tree/master/dubbo-demo/dubbo-demo-provider

'use strict';

const { RpcClient } = require('sofa-node-rpc').client;
const { ZookeeperRegistry } = require('sofa-node-rpc').registry;
const protocol = require('dubbo-remoting');
const logger = console;

const registry = new ZookeeperRegistry({
  logger,
  address: '127.0.0.1:2181/dubbo/',  // 注意:这里需要以 /dubbo/ 结尾
});

async function invoke() {
  const client = new RpcClient({
    logger,
    registry,
    protocol,
    group: 'dubbo', // 这个根据实际情况填
    version: null, // 这个根据实际情况填
  });
  const consumer = client.createConsumer({
    interfaceName: 'org.apache.dubbo.demo.DemoService',
  });
  await consumer.ready();

  const result = await consumer.invoke('sayHello', [{
    $class: 'java.lang.String',
    $: 'zongyu',
  }], { responseTimeout: 3000 });
  console.log(result);
}

invoke().catch(console.error);
JimmyDaddy commented 6 years ago

我按照 demo 试了一下,注册中心连接成功了,但是 group 的设置貌似依然不对 这里是我的代码:

'use strict'

const { RpcClient } = require('sofa-rpc-node').client
const { ZookeeperRegistry } = require('sofa-rpc-node').registry
const { RpcServer } = require('sofa-rpc-node').server
const protocol = require('dubbo-remoting')
const logger = console

const registry = new ZookeeperRegistry({
  logger,
  address: '127.0.0.1:2181/dubbo/'
})
async function call() {
  const client = new RpcClient({
    logger: app.logger,
    protocol,
    registry,
    group: 'HSF'
  })

  const consumer = client.createConsumer({
    interfaceName: 'com.demo.provider.UserBaseQueryProvider',
    version: '1.0.0.dev' //指定版本
  })

  await consumer.ready()

  const result = await consumer.invoke('getUserInfo',
    [{
      $class: ' com.demo.provider.param.UserInfoQueryDTO',
      $: {
        mobilePhoneLike: {
          $class: 'java.lang.String',
          $: '157'
        }
      }
    }], {
      responseTimeout: 3000
    })
  console.log('==============result======================')
  console.log(result)
  console.log('====================================')
  return result
}

结果运行报错:

com.alibaba.dubbo.remoting.RemotingException: 
Not found exported service: 
com.demo.provider.UserBaseQueryProvider: 1.0 .0.dev: 21880 
in 
[
  HSF / com.demo.provider.UserBaseProvider: 1.0 .0.dev: 21880,  
  HSF / com.demo.provider.customer.CustomerIdentityProvider: 1.0 .0.dev: 21880, 
  HSF / com.demo.testclient.provider.city.BaseUserCityRelationshipProvider: 1.0 .0.dev: 21880, 
  HSF / com.demo.testclient.provider.permission.menu.PermissionMenuProvider: 1.0 .0.dev: 21880, 
  HSF / com.demo.provider.UserBaseTagProvider: 1.0 .0.dev: 21880,
  HSF / com.demo.provider.UserBaseQueryProvider: 1.0 .0.dev: 21880
], 
may be version or group mismatch, channel: consumer: /121.*.*.1:55359 --> provider: /
121.*.* .202: 21880, message: RpcInvocation[
  methodName = getUserInfo, 
  parameterTypes = [class com.demo.provider.param.UserInfoQueryDTO], 
  arguments = [com.demo.provider.param.UserInfoQueryDTO @86f0588], 
  attachments = {
    path = com.demo.provider.UserBaseQueryProvider,
    input = 433,
    service = com.demo.provider.UserBaseQueryProvider: 1.0 .0.dev,
    dubbo = 5.3 .0,
    version = 1.0 .0.dev
  }
]

并且程序还尝试了去连接这个接口的另外两个版本(1.0.0.daily 和 1.0.0.test)(我并没有去指定连接它们),抛出警告:

2018-10-30 10:52:27,188 WARN 15449 [ConnectionManager] create connection: dubbo://10.*.*.68:12210/com.demo.provider.UserBaseQueryProvider?ROUTE=-1&_CONTAINERID=ecc:e63288c0-17ca-4d62-bb79-a765c447d2fb&_ENV=DEFAULT&_SERIALIZETYPE=hessian&_TID=dcc6f6d8-6697-4d65-b520-5c4ae10d507f&_TIMEOUT=3000&_ih2=y&_p=hessian2&application=d58921e6-953c-4f37-9228-efd1b6413eb1&dubbo=2.6.1&group=HSF&interface=com.demo.provider.UserBaseQueryProvider&side=provider&timeout=3000&v=2.0&version=1.0.0.daily failed, caused by socket#dubbo://10.*.*.68:12210/com.demo.provider.UserBaseQueryProvider?ROUTE=-1&_CONTAINERID=ecc:e63288c0-17ca-4d62-bb79-a765c447d2fb&_ENV=DEFAULT&_SERIALIZETYPE=hessian&_TID=dcc6f6d8-6697-4d65-b520-5c4ae10d507f&_TIMEOUT=3000&_ih2=y&_p=hessian2&application=d58921e6-953c-4f37-9228-efd1b6413eb1&dubbo=2.6.1&group=HSF&interface=com.demo.provider.UserBaseQueryProvider&side=provider&timeout=3000&v=2.0&version=1.0.0.daily connect timeout(3000ms)
2018-10-30 10:52:27,189 WARN 15449 [ConnectionManager] create connection: dubbo://172.*.*.6:12202/com.demo.provider.UserBaseQueryProvider?APP=f42e78eb-d28c-4921-b058-248e99841976&ROUTE=-1&_CONTAINERID=ecc:8b6b6208-8dce-4b68-a80d-b2f3240363ee&_ENV=DEFAULT&_SERIALIZETYPE=hessian&_TID=5c098aaa-2bf1-4782-a641-fd63ec280452&_TIMEOUT=3000&_p=hessian2&application=f42e78eb-d28c-4921-b058-248e99841976&dubbo=2.6.1&group=HSF&interface=com.demo.provider.UserBaseQueryProvider&side=provider&timeout=3000&v=2.0&version=1.0.0.test failed, caused by socket#dubbo://172.*.*.6:12202/com.demo.provider.UserBaseQueryProvider?APP=f42e78eb-d28c-4921-b058-248e99841976&ROUTE=-1&_CONTAINERID=ecc:8b6b6208-8dce-4b68-a80d-b2f3240363ee&_ENV=DEFAULT&_SERIALIZETYPE=hessian&_TID=5c098aaa-2bf1-4782-a641-fd63ec280452&_TIMEOUT=3000&_p=hessian2&application=f42e78eb-d28c-4921-b058-248e99841976&dubbo=2.6.1&group=HSF&interface=com.demo.provider.UserBaseQueryProvider&side=provider&timeout=3000&v=2.0&version=1.0.0.test connect timeout(3000ms)
gxcsoccer commented 6 years ago

我大概知道了,稍等

gxcsoccer commented 6 years ago

https://github.com/alipay/sofa-rpc-node/pull/18

@JimmyDaddy 重新安装一下,再试试

JimmyDaddy commented 6 years ago

问题还是存在的 我在 1.5.1 版本里面 通过 registry 报错:

no provider of *** found!

直连是可以成功的, 我稍微看了一下,貌似还是 address 获取失败的原因


  async getConnection(req) {
    const meta = req.meta;
    meta.connectionGroup = this.key;

    const address = this._loadbalancer.select(req); // address 为 null
    if (!address) return null;

    const { connectionOpts, connectionClass } = this.options;
    return await this.connectionManager.createAndGet(address, connectionOpts, connectionClass);
  }

测试代码和上面的 demo 一样

gxcsoccer commented 6 years ago

@JimmyDaddy 把完整的日志给我

gxcsoccer commented 6 years ago

要具体看下订阅到的 url,之前都可以访问到机器,只是 group 没有匹配上,现在找不到,说明是新加的逻辑把它过滤掉了

JimmyDaddy commented 6 years ago

日志并不多,仅仅抛出了一个我上面提到的错误; 我看了看源码打了些日志,执行请求时:

其中 `  this._zkClient.watchChildren` 返回的 四个版本的 children 是我们已有的四个版本,分别为:

* `dubbo://192.168.0.59:21880/com.demo.provider.UserBaseQueryProvider?anyhost=true&application=user-service&default.group=HSF&default.version=1.0.0.yrc&dubbo=2.0.1&generic=false&interface=com.provider.UserBaseQueryProvider&logger=slf4j&methods=getListUserProperty,getMDSUserInfoByEdata,getByIds,getById,getByPhoneAndPassword,getByEdata,getUserInfoPage,getMockUserInfoByCatGroupId,getUserInfo,getByMobilePhone&pid=1379&revision=1.0.0-SNAPSHOT&side=provider&timestamp=1541040082598` 
这一个的 provider 是局域网 ip,
它的 providerInfo 为 :

URLSearchParams { 'anyhost' => 'true', 'application' => 'user-service', 'default.group' => 'HSF', 'default.version' => '1.0.0.yrc', 'dubbo' => '2.0.1', 'generic' => 'false', 'interface' => 'com.demo.provider.UserBaseQueryProvider', 'logger' => 'slf4j', 'methods' => 'getListUserProperty,getMDSUserInfoByEdata,getByIds,getById,getByPhoneAndPassword,getByEdata,getUserInfoPage,getMockUserInfoByCatGroupId,getUserInfo,getByMobilePhone', 'pid' => '30009', 'revision' => '1.0.0-SNAPSHOT', 'side' => 'provider', 'timestamp' => '1540797787690' }


* `dubbo://121.*.*.*:21880/com.demo.provider.UserBaseQueryProvider?anyhost=true&application=user-service&default.group=HSF&default.version=1.0.0.dev&dubbo=2.0.1&generic=false&interface=com.provider.UserBaseQueryProvider&logger=slf4j&methods=getListUserProperty,getMDSUserInfoByEdata,getByIds,getById,getByPhoneAndPassword,getByEdata,getUserInfoPage,getMockUserInfoByCatGroupId,getUserInfo,getByMobilePhone&pid=30009&revision=1.0.0-SNAPSHOT&side=provider&timestamp=1540797787690` 
这一个就是我要访问的那一个版本(1.0.0.dev)的 provider ,宿主是外网 ip 可访问的,直连能返回数据,但是通过 registry 就无法定位到它了,而且这个和 下面两个可定位到的 provider 有很大的不同 ,
它的 providerInfo 为:

URLSearchParams { 'anyhost' => 'true', 'application' => 'user-service', 'default.group' => 'HSF', // group 和 version 变为了 default.group 和 default.version 'default.version' => '1.0.0.dev', 'dubbo' => '2.0.1', 'generic' => 'false', 'interface' => 'com.demo.provider.UserBaseQueryProvider', 'logger' => 'slf4j', 'methods' => 'getListUserProperty,getMDSUserInfoByEdata,getByIds,getById,getByPhoneAndPassword,getByEdata,getUserInfoPage,getMockUserInfoByCatGroupId,getUserInfo,getByMobilePhone', 'pid' => '30009', 'revision' => '1.0.0-SNAPSHOT', 'side' => 'provider', 'timestamp' => '1540797787690' }


* `dubbo://172.*.*.6:12200/com.demo.provider.UserBaseQueryProvider?APP=f42e78eb-d28c-4921-b058-248e99841976&ROUTE=-1&_CONTAINERID=ecc:8b6b6208-8dce-4b68-a80d-b2f3240363ee&_ENV=DEFAULT&_SERIALIZETYPE=hessian&_TID=5c098aaa-2bf1-4782-a641-fd63ec280452&_TIMEOUT=3000&_p=hessian2&application=f42e78eb-d28c-4921-b058-248e99841976&dubbo=2.6.1&group=HSF&interface=com.provider.UserBaseQueryProvider&side=provider&timeout=3000&v=2.0&version=1.0.0.test` 
这一个是属于内网 ip,我尝试过访问该版本的服务,能够定位到这个服务,因为内网 Ip 的缘故连接时 timeout ,

providerInfo 为 :

URLSearchParams { 'ROUTE' => '-1', '_CONTAINERID' => 'ecc:e63288c0-17ca-4d62-bb79-a765c447d2fb', '_ENV' => 'DEFAULT', '_SERIALIZETYPE' => 'hessian', '_TID' => 'dcc6f6d8-6697-4d65-b520-5c4ae10d507f', '_TIMEOUT' => '3000', '_ih2' => 'y', '_p' => 'hessian2', 'application' => 'd58921e6-953c-4f37-9228-efd1b6413eb1', 'dubbo' => '2.6.1', 'group' => 'HSF', 'interface' => 'com.demo.provider.UserBaseQueryProvider', 'side' => 'provider', 'timeout' => '3000', 'v' => '2.0', 'version' => '1.0.0.test' }


* `dubbo://10.*.*.68:12210/com.demo.provider.UserBaseQueryProvider?ROUTE=-1&_CONTAINERID=ecc:e63288c0-17ca-4d62-bb79-a765c447d2fb&_ENV=DEFAULT&_SERIALIZETYPE=hessian&_TID=dcc6f6d8-6697-4d65-b520-5c4ae10d507f&_TIMEOUT=3000&_ih2=y&_p=hessian2&application=d58921e6-953c-4f37-9228-efd1b6413eb1&dubbo=2.6.1&group=HSF&interface=com.provider.UserBaseQueryProvider&side=provider&timeout=3000&v=2.0&version=1.0.0.daily`
这一个是属于内网 ip,我尝试过访问该版本的服务,也能够定位到这个服务,因为内网 Ip 的缘故连接时 timeout ,
providerInfo 为 :

URLSearchParams { 'ROUTE' => '-1', '_CONTAINERID' => 'ecc:e63288c0-17ca-4d62-bb79-a765c447d2fb', '_ENV' => 'DEFAULT', '_SERIALIZETYPE' => 'hessian', '_TID' => 'dcc6f6d8-6697-4d65-b520-5c4ae10d507f', '_TIMEOUT' => '3000', '_ih2' => 'y', '_p' => 'hessian2', 'application' => 'd58921e6-953c-4f37-9228-efd1b6413eb1', 'dubbo' => '2.6.1', 'group' => 'HSF', 'interface' => 'com.demo.provider.UserBaseQueryProvider', 'side' => 'provider', 'timeout' => '3000', 'v' => '2.0', 'version' => '1.0.0.daily' }


***前两个是直接注册到 zk 上的,后两个则是通过 edas 注册到 zk 上的,并且前两个的 dubbo 版本 为 2.0.1 ,后两个版本为 2.6.1***

我发现问题出在 `data_client.js` 的 `_isMatch` 方法上:
```javascript
 _isMatch(consumer, urlStr) {
    const url = new URL(urlStr);
    const providerInfo = url.searchParams || {};
    const interfaceName = providerInfo.get('interface') || url.pathname.slice(1);
    if (interfaceName && consumer.interfaceName !== interfaceName) {
      return false;
    }
    const category = providerInfo.get('category');
    if (category && category !== 'providers') {
      return false;
    }
    const enabled = providerInfo.get('enabled');
    if (enabled && enabled !== 'true') {
      return false;
    }
    const consumerGroup = consumer.group;
    const consumerVersion = consumer.version;
    const providerGroup = providerInfo.get('group'); // group 有可能为 default.group
    const providerVersion = providerInfo.get('version'); // version 有可能为 default.version
    return (!consumerGroup || consumerGroup === providerGroup) &&
      (!consumerVersion || consumerVersion === providerVersion);
  }

我将 _isMatch 里面的两行代码改了一下:

    const providerGroup = providerInfo.get('group');
    const providerVersion = providerInfo.get('version');

改为

    const providerGroup = providerInfo.get('group') || providerInfo.get('default.group');
    const providerVersion = providerInfo.get('version') || providerInfo.get('default.version');

就能访问成功了

gxcsoccer commented 6 years ago

@JimmyDaddy ok,我改下

gxcsoccer commented 6 years ago

@JimmyDaddy 再试试

JimmyDaddy commented 6 years ago

好了,没问题了@gxcsoccer 谢谢