一、什么是RPC
RPC(Remote Procedure Call)远程过程调用,简单的理解就是一个节点服务器中的服务请求另一个节点服务器中的服务。如果使用常用的http请求肯定可以实现,但是如何做的的更好这就是RPC要来解决的问题。它需要调用远程服务就跟调用本地一样简单。比如本地调用:
# 定义一个函数 def sub(a: int, b: int) -> int: return a - b # 本地调用函数 res = sub(10, 5) print(res)
本地调用sub函数就是这样一个简单的过程,远程过程调用就需要达到一个这样的效果。那么假如现在将sub函数放到远程服务器上,就会面临一些问题:
- 如果远程服务器上有很多sub函数,你通过函数名怎么区分到底调用的是哪一个呢?
- 函数sub的参数传递,现在不是在本地,不是在同一个进程中,如果进行参数传递呢?
- 既然是远程的,那么势必会涉及到网络传输,选择何种传输协议进行网络传输呢?
1、call id映射
因为本地和远程的内存空间不同,所以不能使用函数名来区分不同的函数了,需要通过call id来进行区分,在远程服务端和本地分别维护着一个call id和函数对应的表,这样本地的调用的函数远程通过查询相应的call id就知道调用的是哪个了。
2、序列化和反序列化
远程和本地之间的传参不能通过像本地调用函数一样了,因为不在一个进程中,所以它们之间的数据传输需要寻求一种方式,就是序列化和反序列化,本地将参数通过一定的方式转成字节流传递给远程,这就是序列化;而远程通过相反的逻辑将其还原成原先的模样这就是反序列化。
3、网络传输
既然不是本地调用,就必然涉及网络传输,网络传输可以使用TCP、UDP、HTTP等协议,只要两侧保持一致即可。
二、RPC调用过程
(1)客户端以本地调用方式调用服务
(2)client stub接收到调用后负责将方法、参数组装序列化后进行网络传输的数据格式
(3)client stub向服务器发送请求
(4)server stub收到消息后进行反序列化
(5)server stub根据反序列后的结果调用本地服务
(6)本地服务执行代码后将结果返回给server stub
(7)server stub将返回结果序列化成一定的数据格式再发送给客户端
(8)client stub接收到消息后进行反序列化
(9)客户端得到最终调用的结果