RPC原理架构

RPC 的实现原理架构图如下所示:

06_RPC原理架构.png

RPC 的服务消费方与提供方如下所示:

07_RPC原理架构.png

这张图非常重点,是 PRC 的基本原理,也就是说两台服务器 A,B,一个应用部署在 A 服务器上,想要调用 B 服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

比如说,A 服务器想调用 B 服务器上的一个方法:

User getUserByName(String userName)
  1. 建立通信

    首先要解决通讯的问题:即 A 机器想要调用 B 机器,首先得建立起通信连接。

    主要是通过在客户端和服务器之间建立 TCP 连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。

    通常这个连接可以是按需连接(需要调用的时候就先建立连接,调用结束后就立马断掉),也可以是长连接(客户端和服务器建立起连接之后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效),多个远程过程调用共享同一个连接。

  2. 服务寻址

    要解决寻址的问题,也就是说,A 服务器上的应用怎么告诉底层的 RPC 框架,如何连接到B服务器(如主机或 IP 地址)以及特定的端口,方法的名称名称是什么。

    通常情况下我们需要提供 B 机器(主机名或 IP 地址)以及特定的端口,然后指定调用的方法或者函数的名称以及入参出参等信息,这样才能完成服务的一个调用。

    可靠的寻址方式(主要是提供服务的发现)是 RPC 的实现基石,比如可以采用 Redis 或者 Zookeeper 来注册服务等等。

  3. 网络传输

    1. 序列化

      当 A 机器上的应用发起一个 RPC 调用时,调用方法和其入参等信息需要通过底层的网络协议如 TCP 传输到 B 机器,由于网络协议是基于二进制的,所有我们传输的参数数据都需要先进行序列化(Serialize)或者编组(marshal)成二进制的形式才能在网络中进行传输。然后通过寻址操作和网络传输将序列化或者编组之后的二进制数据发送给 B 机器。

    2. 反序列化

      当 B 机器接收到 A 机器的应用发来的请求之后,又需要对接收到的参数等信息进行反序列化操作(序列化的逆操作),即将二进制信息恢复为内存中的表达方式,然后再找到对应的方法(寻址的一部分)进行本地调用(一般是通过生成代理 Proxy 去调用,通常会有 JDK 动态代理、CGLIB 动态代理、Javassist 生成字节码技术等),之后得到调用的返回值。

  4. 服务调用

    B 机器进行本地调用(通过代理 Proxy 和反射调用)之后得到了返回值,此时还需要再把返回值发送回A机器,同样也需要经过序列化操作,然后再经过网络传输将二进制数据发送回A机器,而当 A 机器接收到这些返回值之后,则再次进行反序列化操作,恢复为内存中的表达方式,最后再交给 A 机器上的应用进行相关处理(一般是业务逻辑处理操作)。

    通常,经过以上四个步骤之后,一次完整的 RPC 调用算是完成了,另外可能因为网络抖动等原因需要重试等。