learn-tech/专栏/RPC实战与核心原理/23如何在没有接口的情况下进行RPC调用?.md
2024-10-16 06:37:41 +08:00

8.0 KiB
Raw Blame History

                        因收到Google相关通知网站将会择期关闭。相关通知内容
                        
                        
                        23 如何在没有接口的情况下进行RPC调用
                        你好我是何小锋。上一讲我们学习了RPC如何通过动态分组来实现秒级扩缩容其关键点就是“动态”与“隔离”。今天我们来聊聊如何在没有接口的情况下进行RPC调用。

应用场景有哪些?

在RPC运营的过程中让调用端在没有接口API的情况下发起RPC调用的需求不只是一个业务方和我提过这里我列举两个非常典型的场景例子。

场景一我们要搭建一个统一的测试平台可以让各个业务方在测试平台中通过输入接口、分组名、方法名以及参数值在线测试自己发布的RPC服务。这时我们就有一个问题要解决我们搭建统一的测试平台实际上是作为各个RPC服务的调用端而在RPC框架的使用中调用端是需要依赖服务提供方提供的接口API的而统一测试平台不可能依赖所有服务提供方的接口API。我们不能因为每有一个新的服务发布就去修改平台的代码以及重新上线。这时我们就需要让调用端在没有服务提供方提供接口的情况下仍然可以正常地发起RPC调用。

场景二我们要搭建一个轻量级的服务网关可以让各个业务方用HTTP的方式通过服务网关调用其它服务。这时就有与场景一相同的问题服务网关要作为所有RPC服务的调用端是不能依赖所有服务提供方的接口API的也需要调用端在没有服务提供方提供接口的情况下仍然可以正常地发起RPC调用。

这两个场景都是我们经常会碰到的而让调用端在没有服务提供方提供接口API的情况下仍然可以发起RPC调用的功能在RPC框架中也是非常有价值的。

怎么做?

RPC框架要实现这个功能我们可以使用泛化调用。那什么是泛化调用呢我们带着这个问题先学习下如何在没有接口的情况下进行RPC调用。

我们先回想下我在基础篇讲过的内容通过前面的学习我们了解到在RPC调用的过程中调用端向服务端发起请求首先要通过动态代理正如[第 05 讲] 中我说过的动态代理可以帮助我们屏蔽RPC处理流程真正地让我们发起远程调用就像调用本地一样。

那么在RPC调用的过程中既然调用端是通过动态代理向服务端发起远程调用的那么在调用端的程序中就一定要依赖服务提供方提供的接口API因为调用端是通过这个接口API自动生成动态代理的。那如果没有接口API呢我们该如何让调用端仍然能够发起RPC调用呢

所谓的RPC调用本质上就是调用端向服务端发送一条请求消息服务端接收并处理之后向调用端发送一条响应消息调用端处理完响应消息之后一次RPC调用就完成了。那是不是说我们只要能够让调用端在没有服务提供方提供接口的情况下仍然能够向服务端发送正确的请求消息就能够解决这个问题了呢

没错,只要调用端将服务端需要知道的信息,如接口名、业务分组名、方法名以及参数信息等封装成请求消息发送给服务端,服务端就能够解析并处理这条请求消息,这样问题就解决了。过程如下图所示:

现在我们已经清楚了解决问题的关键但RPC的调用端向服务端发送消息是需要以动态代理作为入口的我们现在得继续想办法让调用端发送我刚才讲过的那条请求消息。

我们可以定义一个统一的接口GenericService调用端在创建GenericService代理时指定真正需要调用的接口的接口名以及分组名而GenericService接口的$invoke方法的入参就是方法名以及参数信息。

这样我们传递给服务端所需要的所有信息包括接口名、业务分组名、方法名以及参数信息等都可以通过调用GenericService代理的$invoke方法来传递。具体的接口定义如下

class GenericService {

Object $invoke(String methodName, String[] paramTypes, Object[] params);

}

这个通过统一的GenericService接口类生成的动态代理来实现在没有接口的情况下进行RPC调用的功能我们就称之为泛化调用。

通过泛化调用功能我们可以解决在没有服务提供方提供接口API的情况下进行RPC调用那么这个功能是否就完美了呢

回顾下[第 17 讲] 我过的内容RPC框架可以通过异步的方式提升吞吐量还有如何实现全异步的RPC框架其关键点就是RPC框架对CompletableFuture的支持那么我们的泛化调用是否也可以支持异步呢

当然可以。我们可以给GenericService接口再添加一个异步方法$asyncInvoke方法的返回值就是CompletableFutureGenericService接口的具体定义如下

class GenericService {

Object $invoke(String methodName, String[] paramTypes, Object[] params);

CompletableFuture