Dubbo为什么会提供泛化调用这个功能

原创 吴就业 139 0 2022-02-20

本文为博主原创文章,未经博主允许不得转载。

本文链接:https://wujiuye.com/article/1e78683550514b30a696812cbdf801bb

作者:吴就业
链接:https://wujiuye.com/article/1e78683550514b30a696812cbdf801bb
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。

两年前,笔者读Dubbo源码的时候就看到了泛化调用(GenericService)的逻辑,当时不知道为啥会有这个逻辑,想不明白,于是就跳过了。

两年后再次接触Dubbo才看懂了泛化调用的逻辑,是因为公司内部业务项目用了这个功能。而笔者负责这块功能的易用性改造,也涉及到泛化调用的功能改造。

从同事那了解到,泛化调用主要用于跨业务的调用,例如其它业务项目调支付接口,或者支付业务调其它业务接口。

为什么要用泛化调用,以及泛化调用是啥?

借助泛型理解,例如go语言目前还不支持泛型,实现一个List集合类型,需要为int、string等多种类型都实现一个类(只是举例,实际上虽然go还不支持泛型,但也不需要这样做)。而java支持泛型,一个List类通用。

Dubbo的泛化调用功能就类似于Java语言提供的泛型功能,目的都是通用。

那为什么需要泛化调用功能呢?

在我司主要用于跨业务调用场景。对于跨业务调用场景,两个业务之间的接口交互,不应该依赖对方的代码,也就是不应该要求对方提供一个jar包。

使用Dubbo需要创建一个接口项目,所有业务接口都在这个项目中声明,消费者和提供者都需要依赖这个项目打包后的jar。但跨业务的情况下,我们是否需要暴露所有接口给其它业务呢?显然是不需要的。

在不依赖对方提供jar包情况下,就无法直接通过接口调用,这时候就可以用泛化调用功能实现RPC调用。

因为没引入jar包,没有接口类,也没有请求/响应的DTO类,因此泛化调用需要消费者在调用之前,指定调用的目标接口类名、方法名、方法参数类型,并将pojo参数转为map,提供者响应结果如果是pojo,也需要转为map。

当然,泛化调用还有其它用途。例如,通过泛化调用实现接口测试工具。

这是官方的使用介绍文档:https://dubbo.apache.org/zh/docsv2.7/user/examples/generic-reference/

原生泛化接口:

图片

泛化调用功能改造

为什么要改造?

因为我们修改了Dubbo的使用方式,新的使用方式与原生有些区别,约定返回值必须是一个Result,使用code和message代替原生的抛异常。并且优化了异步调用,封装同步与异步调用的差异逻辑,使其对使用者无感知。

为能继续提供泛化调用功能支持,我们弃用了原生泛化调用接口,自己去实现泛化调用。但依然不需要修改Dubbo源码,得益于Dubbo的扩展性,只需要通过扩展点去实现。

改造后的GenericService接口声明如下。

class GenericInvokeParams {
        private String serviceName;
        private String methodName;
        private String[] paramTypes;
        private Object[] request;
}

public interface GenericService {  
    Result<Object> invoke(InvokeParams params);
}

我们还给Invoker增加了serviceName参数,这样一个GenericService代理实例就能调用任何接口。

改造后的泛化调用使用demo如下:

图片

以使用http协议为例,简单概括下实现原理:

GenericService提供者:

普通调用,以接口类名作为uri暴露接口,泛化调用需要加上“/generic”后缀。因为需要区分处理,泛化调用的处理逻辑与普通调用的处理逻辑不同。

服务提供者在接收到泛化调用请求时,需要将泛化调用转化为普通调用,再走完普通调用的逻辑,然后将返回结果转为泛化调用的返回结果。

GenericService消费者:

在发起请求时,将serviceName参数作为普通调用的uri,并拼接“/generic”后缀作为泛化调用的uri。

根据serviceName获取服务提供者,然后发起远程调用。

实现上涉及到的技术点:动态代理、ProxyFactory扩展点、Protocol扩展点。

#中间件

声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。

文章推荐

Dubbo支持自适应等待无损下线

无损上下线是服务治理不可忽视的问题,在应⽤上下线发布过程中,如果上下线不平滑,就会出现短时间的服务调⽤报错,如连接被拒绝(`Connection refused`)、请求超时或请求异常。

Xxl-job SDK引发的OOM

由于输出的错误日记字符串长度过长,导致xxl-job-admin处理callback请求无法将日记入库。sdk会将失败的callback写入一个重试文件(xxl-job-callback.log),sdk有一个后台线程,定时每几秒会全量load重试文件到内存中...

Dubbo之HTTP RPC vs Dubbo RPC性能压测

此次性能测试对比的是我们基于Dubbo扩展点自实现的Http rpc协议,与Dubbo原生Dubbo rpc协议的单次请求响应平均耗时、吞吐量。

基于扩展点,为dubbo支持跨业务调用

很多规模稍大点的公司,内部都会有多个业务部门,这些业务部门都有自己的业务产品。每个业务部门开发的产品部署的环境物理上也都是相对隔离的,但这些业务部门之间可能存在合作关系,业务关联,因此就有了跨业务RPC调用的需求。

kafka消息重复消费排查

业务使用我们基础部门封装的kafka组件,在一次版本迭代中,我们引入了offset缓存,正是这个缓存,在某种条件触发下,会导致出现消息重复消费现象。

Quartz分布式调度原理

在同一时刻需要触发的Job只有少量的情况下,我们看不到Quartz的性能缺陷,在Job数量明显增加情况下,我们就会发现,调度延迟会有明显增加。尽管横向扩展节点,调度延迟也不会降低,且整体调度性能没有明显好转,反而更糟糕。