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


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

文章插图
 
 
RPC.CALL 工作原理如下图:
 
花了一个星期,我终于把RPC框架整明白了

文章插图
 
 
图 17:RPC.CALL 具体实现图
工作流程:
  • 客户端创建 Message 时指定 reply_to 队列名、correlation_id 标记调用者 。
  • 通过队列,服务端收到消息 。调用函数处理,然后返回 。
  • 返回的队列是 reply_to 指定的队列,并携带 correlation_id 。
  • 返回消息到达客户端,客户端根据 correlation_id 判断是哪一个函数的调用返回 。
如果有多个线程同时进行远程方法调用,这时建立在 Client Server 之间的 Socket 连接上会有很多双方发送的消息传递,前后顺序也可能是随机的 。
Server 处理完结果后,将结果消息发送给 Client,Client 收到很多消息,怎么知道哪个消息结果是原先哪个线程调用的?
Client 线程每次通过 Socket 调用一次远程接口前,生成一个唯一的 ID,即 Request ID(Request ID必需保证在一个 Socket 连接里面是唯一的),一般常常使用 AtomicLong 从 0 开始累计数字生成唯一 ID 。
RPC.CAST
RPC.CAST 的远程调用流程与 RPC.CALL 类似,只是缺少了系统消息响应流程 。
一个 Topic 消息生产者发送系统请求消息到 Topic 交换器,Topic 交换器根据消息的 Routing Key 将消息转发至共享消息队列 。
与共享消息队列相连的所有 Topic 消费者接收该系统请求消息,并把它传递给响应的服务端进行处理 。
其调用流程如图所示:
 
花了一个星期,我终于把RPC框架整明白了

文章插图
 
 
图 18:RPC.CAST 原理图
连接设计
RabbitMQ 实现的 RPC 对网络的一般设计思路:消费者是长连接,发送者是短连接 。但可以自由控制长连接和短连接 。
一般消费者是长连接,随时准备接收处理消息;而且涉及到 RabbitMQ Queues、Exchange 的 auto-deleted 等没特殊需求没必要做短连接 。发送者可以使用短连接,不会长期占住端口号,节省端口资源 。
Nova 中 RPC 代码设计:
 
花了一个星期,我终于把RPC框架整明白了

文章插图
 
 
简单对比 RPC 和 Restful API
RESTful API 架构
REST 最大的几个特点为:资源、统一接口、URI 和无状态 。
①资源
所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息 。它可以是一段文本、一张图片、一首歌曲、一种服务,就是一个具体的实在 。
②统一接口
RESTful 架构风格规定,数据的元操作,即 CRUD(Create,Read,Update 和 Delete,即数据的增删查改)操作,分别对应于 HTTP 方法:GET 用来获取资源,POST 用来新建资源(也可以用于更新资源),PUT 用来更新资源,DELETE 用来删除资源,这样就统一了数据操作的接口,仅通过 HTTP 方法,就可以完成对数据的所有增删查改工作 。
③URL
可以用一个 URI(统一资源定位符)指向资源,即每个 URI 都对应一个特定的资源 。
要获取这个资源,访问它的 URI 就可以,因此 URI 就成了每一个资源的地址或识别符 。
④无状态
所谓无状态的,即所有的资源,都可以通过 URI 定位,而且这个定位与其他资源无关,也不会因为其他资源的变化而改变 。有状态和无状态的区别,举个简单的例子说明一下 。
如查询员工的工资,如果查询工资是需要登录系统,进入查询工资的页面,执行相关操作后,获取工资的多少,则这种情况是有状态的 。
因为查询工资的每一步操作都依赖于前一步操作,只要前置操作不成功,后续操作就无法执行 。
如果输入一个 URI 即可得到指定员工的工资,则这种情况是无状态的,因为获取工资不依赖于其他资源或状态 。
且这种情况下,员工工资是一个资源,由一个 URI 与之对应,可以通过 HTTP 中的 GET 方法得到资源,这是典型的 RESTful 风格 。
RPC 和 Restful API 对比
面对对象不同:
  • RPC 更侧重于动作 。
  • REST 的主体是资源 。
RESTful 是面向资源的设计架构,但在系统中有很多对象不能抽象成资源,比如登录,修改密码等而 RPC 可以通过动作去操作资源 。所以在操作的全面性上 RPC 大于 RESTful 。
传输效率: