背景
因为需要建设测试平台,但是平台需要同时支持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 对象。
缓存失效策略:
- 手动:开放了一个接口:每次出现打错 IP 的情况,手动清理一下这个 Map 对象
- 自动:通过 google 的 Cache 类,设置一个过期时间,比如 3 分钟,缓存自动失效
这个方案的毛病:
- 出现问题都是后知后觉的,测试同学发现问题后,平台开发同学再去清理缓存,整个过程想必测试同学非常的痛苦:好不容易以为发现了一个 bug,结果是你这个辣鸡平台的问题…
- 方案解决方式不长久,就好像是身体里面有一块病灶,你知道在哪里,也不去治理它,久而久之会引发其他问题,并且使得使用平台的同学信心丢失
不使用缓存
官方代码
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
reference.setInterface("com.xxx.XxxService");
reference.setVersion("1.0.0");
reference.setGeneric(true);
GenericService genericService = reference.get();
不使用缓存最大的问题:
- 每次请求接口,相当慢
- 根本没有解决打错 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 提交了工单,希望有人能回复,结果却是:处理问题的人不是专门搞技术的,让我去对应的钉钉群里提问,我…
最终解决方案
最终解决是组内小伙伴不懈的努力才解决的,虽然解决方案不一定是最好的,但是也算是目前为止,对我们而言是最佳的。
解决方式:
- 先通过 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
返回信息: 2. 再通过 dubbo 的直连泛化调用
ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
reference.setUrl("dubbo://" + ip + ":" + port + "/" + "接口名");
注意:
|