Amos的随笔

Java/Python/Go,软件测试等等

导航

【Dubbo泛化调用】同一个服务器上调用不同Nacos注册中心导致 IP 打错的问题处理

背景

因为需要建设测试平台,但是平台需要同时支持Dubbo/Http请求协议方式。

等于是我们的调用接口的服务器需要支持到多环境注册中心,比如说

  • 测试环境:nacos://10.10.10.1:4001?namespace=test
  • 集成环境-A:nacos://10.10.10.2:4001?namespace=sit
  • 集成环境-B:nacos://10.10.10.3:4001?namespace=sit

还需要以泛化调用的方式发起请求,服务消费者是没有服务提供者契约包的。

最初我们是采用的是开源的 jmeter-dubbo-plugins 插件,但是有一个非常致命的问题:

在同名接口(同个服务接口、同样的方法、同样的形参、同个 group、同个 version),但是注册中心地址不同的情况下,第二次的请求会打到第一次请求的注册中心对应服务的 IP 上去;比如先请求了集成 A,再请求集成 B,会导致第二次的请求根本就到不了集成 B 环境。 这是由于 Dubbo 的缓存策略导致。

历程

定时/手动清除缓存

cache = ReferenceConfigCache.getCache(address);

cache这个对象会有一个 Map<address , cache>的映射表,每次先从这里取,取不到就重现生成新的 cache 对象。

缓存失效策略:

  1. 手动:开放了一个接口:每次出现打错 IP 的情况,手动清理一下这个 Map 对象
  2. 自动:通过 google 的 Cache 类,设置一个过期时间,比如 3 分钟,缓存自动失效

这个方案的毛病:

  1. 出现问题都是后知后觉的,测试同学发现问题后,平台开发同学再去清理缓存,整个过程想必测试同学非常的痛苦:好不容易以为发现了一个 bug,结果是你这个辣鸡平台的问题…
  2. 方案解决方式不长久,就好像是身体里面有一块病灶,你知道在哪里,也不去治理它,久而久之会引发其他问题,并且使得使用平台的同学信心丢失

不使用缓存

官方代码

// 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>(); 
// 弱类型接口名
reference.setInterface("com.xxx.XxxService");  
reference.setVersion("1.0.0");
// 声明为泛化接口 
reference.setGeneric(true);  

// 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口引用  
GenericService genericService = reference.get(); 

不使用缓存最大的问题:

  1. 每次请求接口,相当慢
  2. 根本没有解决打错 IP 地址的问题

重写缓存策略

之前的缓存获取是通过org.apache.dubbo.config.utils.ReferenceConfigCache 这个类来拿的,但是它的默认 Key 策略是:

ReferenceConfigBase 属性里面的 Group, Interface and version 组合而成 .
比如:group1/org.apache.dubbo.foo.FooService:1.0.0

我们尝试修改 Key 策略:加上 namespace,加上注册中心的 host/port,然后并没有用,依然是打错 IP 地址。

其他尝试

  • 在 dubbo 的 github 上面提交了 issue,希望有人可以帮忙解决,结果是残酷的,没人回复
  • 加了 dubbo/nacos 的钉钉群,在里面抛出问题的背景和发生过程,有一个同学回复了我,但是跟我的情况不一样,依然无果
  • 在 aliyun 提交了工单,希望有人能回复,结果却是:处理问题的人不是专门搞技术的,让我去对应的钉钉群里提问,我…

最终解决方案

最终解决是组内小伙伴不懈的努力才解决的,虽然解决方案不一定是最好的,但是也算是目前为止,对我们而言是最佳的。

解决方式:

1. 先通过 nacos 注册中心 Open api 查询到该注册中心下对应服务的 host+ip,条件是 如下标红的字段都是true,举个例子:

http://xxx.com:5555/nacos/v1/ns/instance/list?serviceName=providers:com.xxx.yyy.zzz.UserinfoService:1.0.0:&namespaceId=test&groupName=DEFAULT_GROUP&clusterName=DEFAULT&pageSize=10&pageNo=1

返回信息:
dubbo services

 

2. 再通过 dubbo 的直连泛化调用

ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
// 中间的省略
reference.setUrl("dubbo://" + ip + ":" + port + "/" + "接口名");

注意:

  • 设置了直连的 url,不要再设置注册中心任何信息

posted on 2022-02-27 21:13  AmosChen  阅读(75)  评论(0编辑  收藏  举报  来源