什么是RPC?
Remote Procedure Call Protocol,远程过程调用。
什么是“远程”?
先来看下什么是“近”,即“本地函数调用”。
int result = Add(1, 2);
这行代码的时候,到底发生了什么?
- 传递两个入参
- 调用了本地代码段中的函数,执行运算逻辑
- 返回一个出参
这三个动作,都发生在同一个进程空间里,这是本地函数调用。
那有没有办法,调用一个跨进程的函数呢?
典型的,这个进程部署在另一台服务器上。
最容易想到的,两个进程约定一个协议格式,使用Socket通信,来传输:
- 入参
- 调用哪个函数
- 出参
如果能够实现,那这就是“远程”过程调用。
Socket通信只能传递连续的字节流,如何将入参、函数都放到连续的字节流里呢?
假设,设计一个11字节的请求报文:
- 前3个字节填入函数名“add”
- 中间4个字节填入第一个参数“1”
- 末尾4个字节填入第二个参数“2”
同理,可以设计一个4字节响应报文:
- 4个字节填入处理结果“3”
调用方的代码可能变为:
request = MakePacket(“add”, 1, 2);
SendRequest_ToService_B(request);
response = RecieveRespnse_FromService_B();
int result = unMakePacket(respnse);
这4个步骤是:
(1)将传入参数变为字节流;
(2)将字节流发给服务B;
(3)从服务B接受返回字节流;
(4)将返回字节流变为传出参数;
服务方的代码可能变为:
request = RecieveRequest();
args/function = unMakePacket(request);
result = Add(1, 2);
response = MakePacket(result);
SendResponse(response);
这个5个步骤也很好理解:
(1)服务端收到字节流;
(2)将字节流转为函数名与参数;
(3)本地调用函数得到结果;
(4)将结果转变为字节流;
(5)将字节流发送给调用方;
这个过程用一张图描述如下:
调用方与服务方的处理步骤都是非常清晰。
这个过程存在最大的问题是什么呢?
调用方太麻烦了,每次都要关注很多底层细节:
- 入参到字节流的转化,即序列化应用层协议细节
- socket发送,即网络传输协议细节
- socket接收
- 字节流到出参的转化,即反序列化应用层协议细节
能不能调用层不关注这个细节?
可以,RPC框架就是解决这个问题的,它能够让调用方“像调用本地函数一样调用远端的函数(服务)”。