解决方案:【剖析 | SOFARPC 框架】系列之 SOFARPC 泛化调用实现剖析
优采云 发布时间: 2020-11-30 11:18[分析| SOFARPC Framework]系列SOFARPC泛化调用实现分析
大咖啡揭示了爪哇人的种植地?点击免费获得“大厂面试名单”,克服面试的困难〜>>>
沙发
ScalableOpenFinancialArchitecture
它是由Ant Financial独立开发的金融级分布式中间件。它收录构建金融级云原生架构所需的所有组件。这是财务方案中的最佳做法。
本文是E符号宝库中的Mona Rudao撰写的“分析| SOFARPC Framework”的第七章。 “分析| SOFARPC框架”系列由SOFA团队和源代码爱好者编写。项目代码为:官方目录已声明。
当前,SOFABolt源代码分析正在进行中,有兴趣的朋友可以在文章结尾处进行申请
前言
我们知道,在RPC调用中,客户端需要加载服务器提供的接口定义类。但是,这并不总是可行的。因此,产生了对通用调用的需求,一个成熟且功能齐全的RPC框架通常支持通用调用,那么通用调用是什么? SOFARPC如何支持广义调用?如何同时实现?与其他RPC泛化调用有何不同?有什么优势?我们将在本文中一个一个地回答。
广义呼叫简介
当客户端由于某种原因而无法获得服务提供商的接口jar包时,或者客户端是更通用的系统,并且不想依赖于每个服务提供商提供的Facade接口,但是需要调用,然后目前需要泛化调用。
例如:
当使用多种语言开发分布式系统时,假设它是NodeJ,并且NodeJ需要调用Java语言的RPC服务,那么我们需要在两者之间建立一个适应层,以便该适应层可以处理NodeJ。请求,然后将其转发到Java的RPC服务。
某些中间系统功能(例如某些内部网关)需要以统一的方式实现对其他下游系统的调用(在非SPI的情况下),显然不可能一一依赖于下游程序包。
某些在线流量回放系统可以拦截数据采集,然后通过泛化进行呼叫回放,而无需依赖整个站点的应用程序。
在这种情况下,必须不包括所有接口的jar文件,否则它将太肿。实际上,这也是不现实的。每次添加服务器,然后释放并重新启动应用程序时,都不可能添加jar包依赖项。
这时,可以使用通用调用,并且可以将相应的请求打包为通用调用,以便可以在不依赖于接口jar包的情况下以多种语言调用RPC服务以避免重复开发。
SOFARPC的通用呼叫用法
SOFARPC的正式文档非常详细,并且已在正式Wiki泛化调用中进行了详细介绍。同时,在源代码的示例模块中,还可以运行现成的演示。读者可以克隆源代码以进行阅读。在这里,我们简要解释如何使用它,以便每个人都具有直观的理解。
接口定义
通常,有2个用于泛化调用的API,包括5种方法,其中2种方法已被弃用,即3种主要方法。他们是:
<p style="line-height: 1.5em;">/**
* 泛化调用
* @return 正常类型(不能是GenericObject类型)
*/
Object $invoke(String methodName, String[] argTypes, Object[] args);/**
* 支持参数类型无法在类加载器加载情况的泛化调用
* @return 除了JDK等内置类型,其它对象是GenericObject类型
*/
Object $genericInvoke(String methodName, String[] argTypes, Object[] args);/**
* 支持参数类型无法在类加载器加载情况的泛化调用
* @return 返回指定的T类型返回对象
*/
T $genericInvoke(String methodName, String[] argTypes, Object[] args, Class clazz);</p>
$ invoke此方法的使用场景:用户知道参数类型和返回值类型,则可以使用此方法。
$ genericInvoke此方法是重载方法。重载一的使用场景是:如果您的应用程序不知道接口的参数类型和返回值类型,那么此时,您需要使用GenericObject类包装返回值和参数。
$ genericInvoke重载二的使用方案是:如果应用程序不知道接口参数类型,但是知道接口返回值的类型,则无需使用GenericObject作为返回值。
基本上,已经涵盖了常用的集中式场景,可以说功能相当全面。
一般用途
由于篇幅所限,我将不在此处发布演示。如果您有兴趣,可以通过链接查看官方演示或源代码,包括使用SOFARPC API和SOFABoot:
演示Wiki地址:
源代码地址:
SOFARPC泛化调用的设计和实现
接下来,我们将重点介绍SOFARPC如何实现广义调用。
框架调用设计
简单来说,泛化调用的关键是对象表示和序列化。 SOFARPC提供了GenericObject之类的对象来表示参数对象或返回值对象,并将GenericObject对象序列化为目标对象,或者将返回值反序列化为GenericObject对象是SOFARPC泛化的关键。
在这里,我们首先看一下SOFARPC泛化调用的流程图,这将有助于以后理解泛化的实现。
让我们谈谈这张照片:
调用通用化API时,将加载通用化过滤器,该过滤器用于进行一些参数转换并设置序列化工厂类型。
SOFARPC将在使用SOFABolt进行网络调用并将其传递给SOFABolt之前创建一个上下文。上下文收录序列化工厂类型信息。这些信息将确定使用哪个序列化程序,并且该上下文将在整个调用期间内流动。
在SOFABolt正式发送数据之前,它将把GenericObject对象序列化为普通对象的字节流,这样服务提供者就不必关心它是否是泛化调用。从图中可以看出,提供程序不需要进行泛化调用任何更改-这是区分SOFARPC泛化与其他RPC泛化的关键。
提供者成功接收到请求后,可以使用常规的序列化器对数据进行反序列化,而只需正常调用并返回即可。
当使用者的SOFABolt接收到响应数据时,它会根据上下文的序列化类型对返回值进行反序列化,即,将普通字节流反序列化为GenericObject对象,因为客户端可能不知道返回值。
最后,泛化API以获取GenericObject类型的返回值。
从以上过程可以看出,序列化程序在泛化调用中占据了大量空间和作用。对于SOFARPC,对hessian3进行了修改以用于通用调用,以支持通用调用所需的序列化功能。 SOFA-Hessian的变化可以在这里参考。
Hessian概括实现
SOFA-Hessian将com.alipay.hessian.generic软件包添加到了hessian软件包中。该软件包的功能是处理泛化调用。重写的关键是实现或继承SerializerFactory类以及Serializer,Deserializer和其他接口。这里,设计了几个类来描述相应的类型信息,并同时实现这些类的序列化和反序列化。对应关系如下
让我们以GenericObjectSerializer为例。该序列化器重写writeObject方法。此方法的功能是将GenericObject对象序列化为目标对象字节流。也就是说,取出GenericObject的type字段和fields字段并将其组合到目标对象的字节流中。
例如:
有一个类型的RPC对象
<p style="line-height: 1.5em;">public class TestObj {
private String str;
private int num;
}</p>
在通用调用客户端中,您可以直接构造GenericObject对象
<p style="line-height: 1.5em;"> GenericObject genericObject = new GenericObject(
"com.alipay.sofa.rpc.invoke.generic.TestObj");
genericObject.putField("str", "xxxx");
genericObject.putField("num", 222);</p>
这时,GenericObjectSerializer可以使用此信息将GenericObject转换为TestObj对象的字节流。服务提供者可以通过普通的hessian2反序列化来获取对象。
与需要两端都支持通用化的其他RPC框架相比,SOFARPC更加友好。换句话说,如果应用程序要支持通用化,则只需要升级客户端(消费者),而服务器(提供者)就不知道。因为从服务器的角度来看,接收到的对象是完全相同的。您可能会发现很难为复杂类型编写这样的结构。 SOFA-Hessian中提供了工具类
<p style="line-height: 1.5em;">com.alipay.hessian.generic.util.GenericUtils</p>
为帮助用户生成,可以直接使用。
SOFARPC和Dubbo泛化调用比较
让我们介绍泛化调用与行业中其他一些产品之间的比较。首先,让我们介绍一下序列化本身的性能和优点。
序列化本身的比较
在Github上,有Java序列化的基准,可以用作参考。尽管在实际场景中,每个序列化场景都是不同的,但结果可能与此处的基准测试结果有所不同,但仍具有参考意义。从该项目的基准测试可以看出:Json是压缩率还是序列率。与Hessian相比,它具有很大的缺点。
同时,尽管与原创程序,kryo等相比,粗麻布的性能差距很小,但是粗麻布反序列化不需要指定类型,这种优势非常有价值。
Dubbo的普遍呼吁
在许多RPC框架中,Dubbo还提供了通用调用的功能。接下来,让我们谈谈Dubbo的概括。 Dubbo泛化和SOFA RPC泛化之间的最大区别是Dubbo需要服务器支持泛化。因此,如果要提供泛化功能,则还必须升级服务器。这似乎对SOFA RPC不友好。
Dubbo的通用呼叫流程如下:
如您所见,Dubbo的服务器还需要一个通用过滤器才能将Map解析为POJO来解析数据。
摘要
本文主要介绍SOFARPC泛化调用的设计和实现,介绍泛化调用的场景,同时,介绍SOFARPC泛化调用的API的用法,并说明泛化设计和实现SOFARPC的详细信息。最后,对社区中某些RPC框架的通用调用进行了简单的比较。
以下是SOFARPC的概括设计和实现的摘要:
设计目标是:服务器不需要感知它是否是通用的,一切都由客户端处理。
带来的好处是:如果应用程序要支持通用化,则无需更改服务器,只需修改客户端即可。这是其他RPC框架中的广义调用之间的最大区别。
实现方法:通过SOFA-Hessian序列化支持泛化序列化。进行泛化调用时,bolt将根据上下文的序列化标记使用相应的序列化程序,SOFA-Hessian的唯一泛化序列化服务器可以将GenericObject对象序列化为目标对象的字节流,服务器可以正常地对其进行反序列化。 SOFA-Hessian独特的泛化反序列化器还可以将目标返回值反序列化为对象,例如GenericObject。
参考
欢迎再加入并参与SOFABolt源代码分析
SOFABolt源代码分析目录:
我们将逐步详细介绍代码的每个部分的设计和实现,并有望根据以下目录进行操作。以下还收录当前的源代码分析文章声明状态:
如何获取:
直接回复此官方帐户想要声明的文章名称,我们会在确定您的资格后主动与您联系,您可以参加,这是您的演出时间!
相关链接
SOFA文件:
沙发:
SOFARPC:
SOFABolt:
小小的复活节彩蛋
请在这里查看您的ID:
长按以获取分布式架构的干货
欢迎一起构建SOFAStack
本文与微信官方帐户-金融级分布式架构(Antfin_SOFA)分享。