花了一个星期,我终于把RPC框架整明白了( 三 )


TCP 的连接是最常见的,简要分析基于 TCP 的连接:通常 TCP 连接可以是按需连接(需要调用的时候就先建立连接,调用结束后就立马断掉),也可以是长连接(客户端和服务器建立起连接之后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效),多个远程过程调用共享同一个连接 。
所以,要实现一个 RPC 框架,只需要把以下三点实现了就基本完成了:

  • Call ID 映射:可以直接使用函数字符串,也可以使用整数 ID 。映射表一般就是一个哈希表 。
  • 序列化反序列化:可以自己写,也可以使用 Protobuf 或者 FlatBuffers 之类的 。
  • 网络传输库:可以自己写 Socket,或者用 Asio,ZeroMQ,Netty 之类 。
RPC 核心之网络传输协议
在第三节中说明了要实现一个 RPC,需要选择网络传输的方式 。
 
花了一个星期,我终于把RPC框架整明白了

文章插图
 
 
图 10:网络传输
在 RPC 中可选的网络传输方式有多种,可以选择 TCP 协议、UDP 协议、HTTP 协议 。
每一种协议对整体的性能和效率都有不同的影响,如何选择一个正确的网络传输协议呢?首先要搞明白各种传输协议在 RPC 中的工作方式 。
基于 TCP 协议的 RPC 调用
由服务的调用方与服务的提供方建立 Socket 连接,并由服务的调用方通过 Socket 将需要调用的接口名称、方法名称和参数序列化后传递给服务的提供方,服务的提供方反序列化后再利用反射调用相关的方法 。
最后将结果返回给服务的调用方,整个基于 TCP 协议的 RPC 调用大致如此 。
但是在实例应用中则会进行一系列的封装,如 RMI 便是在 TCP 协议上传递可序列化的 JAVA 对象 。
基于 HTTP 协议的 RPC 调用
该方法更像是访问网页一样,只是它的返回结果更加单一简单 。
其大致流程为:由服务的调用者向服务的提供者发送请求,这种请求的方式可能是 GET、POST、PUT、DELETE 等中的一种,服务的提供者可能会根据不同的请求方式做出不同的处理,或者某个方法只允许某种请求方式 。
而调用的具体方法则是根据 URL 进行方法调用,而方法所需要的参数可能是对服务调用方传输过去的 XML 数据或者 JSON 数据解析后的结果,最后返回 JOSN 或者 XML 的数据结果 。
由于目前有很多开源的 Web 服务器,如 Tomcat,所以其实现起来更加容易,就像做 Web 项目一样 。
两种方式对比
基于 TCP 的协议实现的 RPC 调用,由于 TCP 协议处于协议栈的下层,能够更加灵活地对协议字段进行定制,减少网络开销,提高性能,实现更大的吞吐量和并发数 。
但是需要更多关注底层复杂的细节,实现的代价更高 。同时对不同平台,如Android/ target=_blank class=infotextkey>安卓,IOS 等,需要重新开发出不同的工具包来进行请求发送和相应解析,工作量大,难以快速响应和满足用户需求 。
基于 HTTP 协议实现的 RPC 则可以使用 JSON 和 XML 格式的请求或响应数据 。
而 JSON 和 XML 作为通用的格式标准(使用 HTTP 协议也需要序列化和反序列化,不过这不是该协议下关心的内容,成熟的 Web 程序已经做好了序列化内容),开源的解析工具已经相当成熟,在其上进行二次开发会非常便捷和简单 。
但是由于 HTTP 协议是上层协议,发送包含同等内容的信息,使用 HTTP 协议传输所占用的字节数会比使用 TCP 协议传输所占用的字节数更高 。
因此在同等网络下,通过 HTTP 协议传输相同内容,效率会比基于 TCP 协议的数据效率要低,信息传输所占用的时间也会更长,当然压缩数据,能够缩小这一差距 。
使用 RabbitMQ 的 RPC 架构
在 OpenStack 中服务与服务之间使用 RESTful API 调用,而在服务内部则使用 RPC 调用各个功能模块 。
正是由于使用了 RPC 来解耦服务内部功能模块,使得 OpenStack 的服务拥有扩展性强,耦合性低等优点 。
OpenStack 的 RPC 架构中,加入了消息队列 RabbitMQ,这样做的目的是为了保证 RPC 在消息传递过程中的安全性和稳定性 。
下面分析 OpenStack 中使用 RabbitMQ 如何实现 RPC 的调用 。
RabbitMQ 简介
以下摘录自知乎:
对于初学者,举一个饭店的例子来解释这三个分别是什么吧 。不是百分百恰当,但是应该足以解释这三者的区别 。
RPC:假设你是一个饭店里的服务员,顾客向你点菜,但是你不会做菜,所以你采集了顾客要点什么之后告诉后厨去做顾客点的菜,这叫 RPC(remote procedure call),因为厨房的厨师相对于服务员而言是另外一个人(在计算机的世界里就是 Remote 的机器上的一个进程) 。厨师做好了的菜就是RPC的返回值 。


推荐阅读