上一小节,简单熟悉了一下基于 gRPC 的 Hello World Demo 程序,接下来学习 gRPC 的相关概念知识,先来看 RPC:

  • 什么是 RPC ?
  • RPC 的核心概念有哪些?
  • RPC 是调用流程是怎么样的?

Statement: 文中内容多参考自网络博客[地址在文中(末)], 感谢这些作者们!🙂

1. 什么是 RPC ?

RPC (Remote Procedure Call): 是一种进程间通信方式。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而向应用开发者屏蔽远程调用的相关技术细节。也就是说,程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。这是客服端-服务器(C/S)交互的一种方式(调用者caller 是客户端,执行者 executor 是服务器), 通常通过一个 request-response 的消息系统实现。

在 Birrell 和 Nelson 在 1984 发表于 ACM Transactions on Computer Systems 的论文 《Implementing remote procedure calls》 中, 对RPC 也做了经典的诠释:RPC 是指计算机 A 上的进程,调用另外一个计算机 B 上的进程,其中 A 上的调用进程被挂起,而 B 上的调用进程开始执行,当值返回给 A 时,A 进程继续执行。 调用方可以通过使用参数将信息传送给被调用方,而后可以通过传回的结果的到信息。而这一过程,对于开发人员来说是透明的。 —— Ref Link

1.1. RPC 核心概念

在上面提到的论文中,将 RPC 的过程抽象为 5 个概念模型,它们分别是:UserUser-StubRPC-RuntimeServer-StubServer

1.1.1. User

User: 即应用的客户端,是 RPC 的发起者。它的职责是通过本地调用 User-Stub 发送调用,并负责接收 User-Stub 的返回值。本地调用还是远程调用对 User 本身来说是完全透明的

1.1.2. User-Stub

User-Stub: 即客户端的存根对象。存根对象的作用是通过使用本地模拟对象的方式,来屏蔽需要通过远程调用才可以获取的对象。User-Stub 负责三件事:

  • 第一件事情是将需要远程调用的接口、方法以及参数通过事先约定好的协议进行序列化
  • 第二件事情是通过本地的 RPCRuntime 对象将序列化的数据传输到服务端的 RPCRuntime 对象
  • 第三件事情是将服务端的返回值反序列化为 User 可是直接使用的对象

1.1.3. RPCRuntime

RPCRuntime: 即远程调用的运行时对象,它同时存在于客户端和服务端,负责网络间信息的发送接收

1.1.4. Server-Stub

Server-Stub: 即服务端的存根对象,它负责将,由服务端的 RPCRuntime 对象接收到的数据进行反序列化并调用服务端的本地方法,和将服务端的本地方法的返回值序列化后交于服务端的 RPCRuntime

1.1.5. Server

Server: 即应用的服务端。用于真正的处理相关业务逻辑

客户端和服务端需要互相知悉相同的业务方法接口。服务端需要将远程接口到处给客户端;同样,客户端需要将该接口导入。这样,客户端才能像调用本地方法一样去调用相同接口的远程方法。

1.2. RPC 的调用流程

远程调用的过程如下图所示(图片来自:https://www.cs.rutgers.edu/~pxk/417/notes/images/rpc-flow.png):

概况来说,远程过程调用包含如下步骤:(摘录原文)

  1. The client calls a local procedure(过程|程序), called the client stub(存根). The client stub packages(包装) the parameters to the remote procedure (this may involve converting them to a standard format) and builds one or more network messages. The packaging of arguments into a network message is called marshaling and requires serializing all the data elements into a flat array-of-bytes format.
  2. Network messages are sent by the client stub to the remote system (via a system call to the local kernel using sockets interfaces).
  3. Network messages are transferred by the kernel to the remote system via some protocol (either connectionless or connection-oriented).
  4. A server stub, sometimes called the skeleton, receives the messages on the server. It unmarshals the arguments from the messages and, if necessary, converts them from a standard network format into a machine-specific form.
  5. The server stub calls the server function (which, to the client, is the remote procedure), passing it the arguments that it received from the client.
  6. When the server function is finished, it returns to the server stub with its return values.
  7. The server stub converts the return values, if necessary, and marshals them into one or more network messages to send to the client stub.
  8. Messages get sent back across the network to the client stub.
  9. The client stub reads the messages from the local kernel.
  10. The client stub then returns the results to the client function, converting them from the network representation to a local one if necessary.

The client code then continues its execution.

总结:以上步骤就是将客户过程对客户存根发出的本地调用转换成对服务器过程的本地调用,而客户端和服务器都不会意识到中间步骤(2-8)的存在

RPC 的主要好处有两方面:

  • 首先,程序员可以使用过程调用语义去调用远程函数并获取响应结果
  • 其次,简化了编写分布式应用的难度,因为将所有的网络代码隐藏到了存根函数中。应用程序不必再担心像套接字、端口号以及数据的转化和解析等细节问题。在 OSI 参考模型中,RPC 跨越了会话层和表示层。

2. See Also

Thanks to the authors 🙂