RPC原理与实现 | 青训营笔记

127 阅读9分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第15天

1 RPC简介

RPC(Remote Procedure Call)叫作远程过程调用,它是利用网络从远程计算机上请求服务,可以理解为把程序的一部分放在其他远程计算机上执行。通过网络通信将调用请求发送至远程计算机后,利用远程计算机的系统资源执行这部分程序,最终返回远程计算机上的执行结果。

RPC是技术时代革新的产物,奠定了构建分布式应用的理论基础。分布式架构提升了服务的灵活性、可服用性,每个服务都可以弹性扩/缩容。除此之外,分布式架构还实现了计算与存储的高可用性。分布式架构最核心的就是利用RPC解决了服务之间的交互问题。

从硬件技术的发展历程可以看出,人们需要计算机提供更高的效率,多核处理器协同工作的技术推动了进程间通信技术的发展,从而推动RPC的诞生。除了硬件技术的发展,另外一个影响RPC诞生的重要因素就是互联网,RPC完全依赖于互联网。无论多核处理器,还是IPC技术,或者是RPC,本质上都是希望能够共享系统资源、提高资源利用率,在有限的资源内让计算机发挥最大的效率。

2 RPC核心组成

RPC核心组成包括四个部分:client、stub、server 和 RPCRuntime。服务调用者、调用端的本地存根及其中一个RPC通信包的实例存在于调用端的机器上,而服务提供者、服务提供端的存根及另一个RPC通信包的实例存在于被调用的机器上。

  • client(服务调用者)
  • stub(本地存根,也分为调用端和服务端的本地存根)
  • server(服务提供者)
  • RPCRuntime(RPC通信者)

2.1 服务调用者

服务调用者也叫服务消费者,它的职责之一是需要提供调用的接口的全限定名和方法,调用方法的参数给调用端的本地存根;职责之二是从调用端的本地存根中接收执行结构。

例如:爸爸打电话给儿子让儿子做一件事情,需要告诉儿子具体要做的是什么事情,比如让儿子把晚饭做了。爸爸在通知儿子的时候就告诉儿子要做晚饭这件事情。爸爸就是这里所说的服务调用者,而儿子是服务提供者,爸爸调用了儿子做饭这个方法。等儿子做完饭后,爸爸从儿子这里得到的是这次做饭的结果。

2.2 服务提供者

服务提供者的职责就是提供服务,执行接口实现的方法逻辑,也就是为服务提供端的本地存根提供方法的具体实现。上面例子中的儿子就是服务提供者,他提供了做晚饭的方法以供其他人调用。

2.3 本地存根

RPC会带来地址空间被隔离的问题,在远程调用的过程中,服务调用端的地址空间在服务提供端那里都是没有意义的。除了内存地址无法匹配,在不同的机器上还可能出现位宽不同、处理器的大小端不同、编译环境导致的结构体内存布局不同、字符串编码不同等情况,这些情况都会导致在远程调用的过程中服务调用端的函数调用无法本地调用一样正确匹配到真实的函数实现,从而导致函数调用失败。所以在远程调用过程中,服务调用者发起的函数调用让服务提供端精准知道自己应该执行哪个函数就是必须要解决的问题。

本地存根的存在就是为了让远程调用本地调用一样直接进行函数调用,无需关心地址空间隔离、函数不匹配等问题。本地存根的职责就是进行类型和参数化。如果将服务调用者和服务提供者比作两个不同语种的人,那么本地存根就类似翻译员,虽然两人语言不同,但是经过本地存根处理后,两端还是能够正常地传达信息并进行沟通。

本地存根分为服务调用端的本地存根和服务提供端的本地存根。服务调用端的本地存根和服务调用者都属于服务消费端,它们存在于同一台机器上,本地存根会解析函数调用的函数名、参数等信息,整理并且组装这些数据,然后将这些数据安装定义好的协议进行系列化,打包成可传输的消息,交给RPC通信者(RPCRuntime)。服务调用端的本地存根除了会提供函数、参数等数据外,还会处理服务提供端返回的结构,它会将RPCRuntime返回的数据反序列化成服务调用端所需要的数据结果。

从服务调用者的角度来看,本地存根隐藏了远程调用的实现细节,就像是远程服务的一个代理对象,可以让服务调用者感觉调用远程服务方法就像调用本地方法一样。

当服务提供端的RPCRuntime收到请求后,交由服务提供端的本地存根进行参数等数据的转化。服务提供端的本地存根重新转换客户端传递的数据,以便在服务提供端的机器上找到对应的函数,传递正确地参数数据,最终正确执行真实函数的调用。等函数执行完成后,服务提供端会将执行结果返回给服务提供端的本地存根,由本地存根再将结果数据系列化、打包,最后交给RPCRuntime。

2.4 RPC通信者

RPC依赖于互联网,远程过程调用的本质就是远程通信,所以RPC必不可缺的就是通信者。RCPRuntime的主要职责是数据包的传输,数据包的确认、数据包路由和加密等。在服务调用端和服务提供端都有一个RPCRuntime实例,负责双方之间的通信,可靠地将存根传递的数据包传输到另一端。

3 RPC调用过程

RPC调用过程可以分为四个阶段,分别是服务暴露过程、服务发现过程、服务引用过程和方法调用过程。

3.1 服务暴露过程

将服务暴露到远程,这个远程指的是一个统一管理所有应用服务地址和信息的管理中心,此管理中心也被称为注册中心。应用服务暴露到远程的第一步是在本地绑定端口,然后将服务提供端的应用服务信息注册到注册中心。

服务提供端在应用服务启动的时候将服务信息注册到注册中心,还会与注册中心保持心跳保活。如果服务提供端某个节点异常下线,注册中心在一段时间的保活检查后,就会将该节点的信息从注册中心中移除,防止服务调用者把请求发送到此下线的节点上。因为业务迭代迅速,服务端的服务变动及上下线很频繁,通过注册中心管理服务的地址信息可以让客户端动态地感知服务变动,并且客户端不需要再显式地配置服务端地址,只要配置注册中心地址即可,而注册中心集群一般不会变动。

3.2 服务发现过程

服务调用者通过注册中心进行服务发现,服务提供端的地址和端口从注册中心获取。当服务提供端变化时,注册中心能够通知服务调用者有关服务提供端的变化。

3.3 服务引用过程

当服务调用者通过服务发现获取所有服务提供端的地址后,通过负责均衡策略选择其中一个服务提供端的节点进行服务引用。服务引用的过程就是与某一个服务节点建立连接,以及在服务调用端创建接口的代理的过程。其中建立连接也就是两端RPCRuntime建立连接的过程。

3.3 方法调用过程

当服务引用完成后,服务调用端和服务提供端已经建立了连接,可以进行方法的调用:

  1. 服务调用者以本地调用方式调用服务(RPC call),它将需要调用的方法、参数类型、参数传递给服务调用端的本地存根(Client Stub)。
  2. 服务调用端的本地存根收到调用后,负责将方法、参数扥工属具组装成能够进行网络传输的消息体,并将信息传递给RPC通信者。
  3. 服务调用端的RPC通信者通过网络,将消息发送到服务提供端。由服务提供端的RPC通信者接收。服务提供端将接收到的消息传递给服务提供端的本地存根。
  4. 服务提供端的本地存根将收到的消息反序列化。
  5. 服务提供端的本地存根根据反序列化的结果解析出服务调用的方法、参数类型、参数等信息,并调用服务提供方的服务。
  6. 服务提供端执行对应方法后,将执行结果返回给服务提供端的本地存根。
  7. 服务提供端的本地存根将返回结果序列化,并将其打包为可传输的消息体,传递给服务提供端的RPC通信者。
  8. 服务提供端的RPC通信者将消息传递给服务调用端,由服务调用端的RPC通信者接收。服务调用端将接收到的消息传递给自己的本地存根。
  9. 服务调用端的本地存根接收到消息后进行反序列化,反序列化出来的是方法执行的结果,并将结果传递给服务调用端。
  10. 服务调用者得到最终的执行结果。