================================================================================
标题: 如何实现 RPC 框架的要点浅析
作者: 叶飞虎
日期: 2017.02.23
--------------------------------------------------------------------------------
1. 什么是 RPC?
RPC 就是 Remote Procedure Call 三个单词首字母的缩写,其字面意思为:远程过程
调用。而远程过程调用直观说法就是:进程 A 远程调用进程 B 的过程方法。既然是远程调
用则需要涉及网络传输,由此可见 RPC 主要应用于不同主机间的过程调用,也可用于本机
中不同进程之前的过程调用。
简单的说,RPC 就是从一台主机上的进程 A 通过参数传递的方式调用另一台主机上的
进程 B 中的一个函数,并得到返回的结果。因此 RPC 具有以下特点:
a. RPC 会隐藏底层的通讯细节,不需要直接处理如何通信及收发数据。
b. RPC 是一个请求响应模型。客户端发起调用请求,服务端返回请求响应,这类似于
HTTP 的工作方式。
c. RPC 在使用形式上像调用本地函数一样去调用远程的函数。
2. 为什么要用 RPC?
在以前的单机时代,一台主机上可以运行多个进程,假如进程 A 和 B 都要控制打印机
进行打印,而打印机同时只能被一个进程控制操作,这要怎么办才好呢?为了解决这一问题
系统提供了打印服务 C 进程,C 进程有打印任务队列,A 和 B 进程把需要打印生成一个打
印任务,然后向 C 进程提交请求即可。A 和 B 进程与 C 进程之间通信就是 IPC,IPC 就
是 Inter-Process Communication 缩写,其主要功能就是单机中进程之间的相互通信。
到了网络时代,不可能每台主机都配置一台打印机,不同主机需要访问带打印机的主机
时 IPC 已无能为力。这时就需要把 IPC 扩展到网络上,而网络通信有很多通讯协议,如:
TCP、UDP等等。不同通讯协议的控制方式不同,这给开发人员带来困难,只要不同主机之间
涉及网络通信,其需要考虑的因素就非常多了,如:网速、断线、延时、私有性、安全性等
等。于是 RPC 就是为简化远程调用应运而生了,开发人员使用 RPC 时无须考虑如何握手连
接、如何收发数据等等问题。
什么时候要用到 RPC 呢?就是无法在单个进程内,甚至单个主机内通过本地调用的方
式完成的需求,比如不同的系统之间的通讯,甚至不同的组织间的通讯。例如计算能力需要
横向扩展,需要在多台主机组成的集群上部署应用,同时要简化通讯细节,这时 RPC 框架
就发挥作用了。集群部署的本质就是分布式服务,由此可见 RPC 框架是分布式服务的基石,
实现 RPC 框架需要考虑方方面面。其对业务隐藏了底层通信过程: TCP/UDP通讯协议、函数
参数打包/解包、参数数据序列化/反序列化,使开发人员专注于功能实现。
3. RPC 框架分层
我们可以对 RPC 框架进行抽丝剥茧,并从层次上把 RPC 分为四层:RPC 物理通讯层、
RPC 通讯协议层、RPC 连接会话层、RPC 应用层。
a. RPC 物理通讯层,根据实际用途可以选择合适的实际物理通讯协议:
1). 可以使用 TCP 网络通讯协议,直接调用套接字 socket 接口函数或者 IOCP 接
口函数进行封装;
2). 可以使用 UDP 网络通讯协议,但必须自己来维护数据包的时序、丢包重传、以
及虚拟连接状态。虽然使用 UDP 相对比较麻烦一点,但是 UDP 也有很多优点,
如:NAT 穿透相对容易、每包数据完整等等;
3). 可以使用 SHM 共享内存通信,用于同一主机不同进程之间的 RPC 调用,优点
是传输速度快,缺点是只能在同一主机上运行;
4). 可以使用第三方通讯模块接口,如:蓝牙、串口、USB连线接口等等。优点是可
以跨终端设备进行相互调用、缺点是受制于第三方通讯模块接口。
b. RPC 通讯协议层就是通讯双方的消息包定义,以及每种消息的数据组织,只需要负
责收发的数据流,具体如何收发数据由物理通讯层去处理。
1). 消息包 = <消息头> + [消息体],也就是说由消息头和消息体组成一个消息包;
2). 消息头必须含有:消息包ID、消息类型、消息体长度、函数ID和调用返回码。
消息头若要做得更完善还可以添加检验码等等,但消息头所占尺寸不宜太大,
否则 RPC 的调用开销就更大了。
3). 消息类型至少含有以下几种:
a). 心跳,含请求和应答;
b). 连接握手,含请求和应答;
c). 登录应用,含请求和应答;
d). 登出应用,含请求和应答;
e). 取定义集,含请求和应答,即读取已登录应用的函数定义集;
f). 调用函数,含请求和应答;
g). 函数取消,即取消已提交的调用函数请求;
h). 函数确认,即函数返回结果确认;
i). 发送数据,用于扩展 RPC 为数据包通讯。
c. RPC 连接会话层,负责通讯双方的连接状态管理,包括以下几个方面:
1). 通过连接握手来确认会话双方的合法性;
2). 通过心跳维护连接在线情况;
3). 通过登录应用来获取对方应用提供的函数定义集,只有知道函数的参数和返回
值定义才可以调用函数,函数定义是参数和返回值的序列化/反序列化前提;
4). 通过登出应用来关闭对端提供的函数调用;
5). 管理函数调用的整个生命周期;
6). 管理发送数据包缓冲队列、以及接收到数据包的处理。
d. RPC 应用层,负责应用内的函数定义、管理连接的登录登出、分配函数调用请求。
1). 在函数定义中,函数参数和返回值的数据类型要支持足够多,不同数据类型可
以便于数据展示,也增加了 RPC 框架的灵活性。同时被 RPC 调用的函数回调
标题: 如何实现 RPC 框架的要点浅析
作者: 叶飞虎
日期: 2017.02.23
--------------------------------------------------------------------------------
1. 什么是 RPC?
RPC 就是 Remote Procedure Call 三个单词首字母的缩写,其字面意思为:远程过程
调用。而远程过程调用直观说法就是:进程 A 远程调用进程 B 的过程方法。既然是远程调
用则需要涉及网络传输,由此可见 RPC 主要应用于不同主机间的过程调用,也可用于本机
中不同进程之前的过程调用。
简单的说,RPC 就是从一台主机上的进程 A 通过参数传递的方式调用另一台主机上的
进程 B 中的一个函数,并得到返回的结果。因此 RPC 具有以下特点:
a. RPC 会隐藏底层的通讯细节,不需要直接处理如何通信及收发数据。
b. RPC 是一个请求响应模型。客户端发起调用请求,服务端返回请求响应,这类似于
HTTP 的工作方式。
c. RPC 在使用形式上像调用本地函数一样去调用远程的函数。
2. 为什么要用 RPC?
在以前的单机时代,一台主机上可以运行多个进程,假如进程 A 和 B 都要控制打印机
进行打印,而打印机同时只能被一个进程控制操作,这要怎么办才好呢?为了解决这一问题
系统提供了打印服务 C 进程,C 进程有打印任务队列,A 和 B 进程把需要打印生成一个打
印任务,然后向 C 进程提交请求即可。A 和 B 进程与 C 进程之间通信就是 IPC,IPC 就
是 Inter-Process Communication 缩写,其主要功能就是单机中进程之间的相互通信。
到了网络时代,不可能每台主机都配置一台打印机,不同主机需要访问带打印机的主机
时 IPC 已无能为力。这时就需要把 IPC 扩展到网络上,而网络通信有很多通讯协议,如:
TCP、UDP等等。不同通讯协议的控制方式不同,这给开发人员带来困难,只要不同主机之间
涉及网络通信,其需要考虑的因素就非常多了,如:网速、断线、延时、私有性、安全性等
等。于是 RPC 就是为简化远程调用应运而生了,开发人员使用 RPC 时无须考虑如何握手连
接、如何收发数据等等问题。
什么时候要用到 RPC 呢?就是无法在单个进程内,甚至单个主机内通过本地调用的方
式完成的需求,比如不同的系统之间的通讯,甚至不同的组织间的通讯。例如计算能力需要
横向扩展,需要在多台主机组成的集群上部署应用,同时要简化通讯细节,这时 RPC 框架
就发挥作用了。集群部署的本质就是分布式服务,由此可见 RPC 框架是分布式服务的基石,
实现 RPC 框架需要考虑方方面面。其对业务隐藏了底层通信过程: TCP/UDP通讯协议、函数
参数打包/解包、参数数据序列化/反序列化,使开发人员专注于功能实现。
3. RPC 框架分层
我们可以对 RPC 框架进行抽丝剥茧,并从层次上把 RPC 分为四层:RPC 物理通讯层、
RPC 通讯协议层、RPC 连接会话层、RPC 应用层。
a. RPC 物理通讯层,根据实际用途可以选择合适的实际物理通讯协议:
1). 可以使用 TCP 网络通讯协议,直接调用套接字 socket 接口函数或者 IOCP 接
口函数进行封装;
2). 可以使用 UDP 网络通讯协议,但必须自己来维护数据包的时序、丢包重传、以
及虚拟连接状态。虽然使用 UDP 相对比较麻烦一点,但是 UDP 也有很多优点,
如:NAT 穿透相对容易、每包数据完整等等;
3). 可以使用 SHM 共享内存通信,用于同一主机不同进程之间的 RPC 调用,优点
是传输速度快,缺点是只能在同一主机上运行;
4). 可以使用第三方通讯模块接口,如:蓝牙、串口、USB连线接口等等。优点是可
以跨终端设备进行相互调用、缺点是受制于第三方通讯模块接口。
b. RPC 通讯协议层就是通讯双方的消息包定义,以及每种消息的数据组织,只需要负
责收发的数据流,具体如何收发数据由物理通讯层去处理。
1). 消息包 = <消息头> + [消息体],也就是说由消息头和消息体组成一个消息包;
2). 消息头必须含有:消息包ID、消息类型、消息体长度、函数ID和调用返回码。
消息头若要做得更完善还可以添加检验码等等,但消息头所占尺寸不宜太大,
否则 RPC 的调用开销就更大了。
3). 消息类型至少含有以下几种:
a). 心跳,含请求和应答;
b). 连接握手,含请求和应答;
c). 登录应用,含请求和应答;
d). 登出应用,含请求和应答;
e). 取定义集,含请求和应答,即读取已登录应用的函数定义集;
f). 调用函数,含请求和应答;
g). 函数取消,即取消已提交的调用函数请求;
h). 函数确认,即函数返回结果确认;
i). 发送数据,用于扩展 RPC 为数据包通讯。
c. RPC 连接会话层,负责通讯双方的连接状态管理,包括以下几个方面:
1). 通过连接握手来确认会话双方的合法性;
2). 通过心跳维护连接在线情况;
3). 通过登录应用来获取对方应用提供的函数定义集,只有知道函数的参数和返回
值定义才可以调用函数,函数定义是参数和返回值的序列化/反序列化前提;
4). 通过登出应用来关闭对端提供的函数调用;
5). 管理函数调用的整个生命周期;
6). 管理发送数据包缓冲队列、以及接收到数据包的处理。
d. RPC 应用层,负责应用内的函数定义、管理连接的登录登出、分配函数调用请求。
1). 在函数定义中,函数参数和返回值的数据类型要支持足够多,不同数据类型可
以便于数据展示,也增加了 RPC 框架的灵活性。同时被 RPC 调用的函数回调