rpc

发布时间 2023-04-17 23:38:34作者: drewwestlhq

概念

RPC(Remote Procedure Call,远程过程调用)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。
 
 

原理

通俗来讲,假设有两台服务器 A,B,有两个程序(程序 1 和程序 2)分别部署在这两台服务器上。由于是两台机器,因此它们的 IP 地址,内存空间等等肯定是不共享的,那程序 1 如何调用到程序 2 的方法呢?

这时我们就需要约定一个协议,让两台机器上的应用程序进行通信,RPC 就是这样一个协议,它通过以下几个步骤来让两个程序识别对方的身份:

  1. 两台机器分别发送和接收数据,所以一个充当服务端,一个充当客户端,它们之间需建立 TCP 连接(按需调用,可以是短连接,也可以是长连接);
  2. 连接 TCP 连接前,客户端需要先知道服务端的 IP 地址和端口号,其中 IP 地址是网络中主机的唯一标识,端口号是主机上应用程序(又叫进程)的唯一标识;
  3. 通信之前,服务端先运行应用程序,监听对应的进程端口号;
  4. 客户端发起 RPC 远程过程调用,把程序交互的参数传给服务端,服务端根据接收的数据处理完成后再传输回客户端,断开此次 TCP 连接,调用结束。
整个过程如下图所示:
  • Client Stub(客户端存根):存放通信的服务器地址消息,并将客户端的请求打包成可以在网络中传输的消息体;
  • Server Stub(服务端存根):接收客户端发送的消息,并将返回结果打包成可以在网络中传输的消息体。
  • Sockets(网络套接字):应用程序的一组程序接口,可用在网络中不同主机之间进行数据交换。

RPC与HTTP

了解完 RPC 之后,可能有些人还是疑惑:既然都是通信协议,那程序交互和应用开发时,我们该选择 HTTP(HyperText Transfer Protocol,超文本传输协议)还是 RPC 协议呢?

这就得从它们两者的属性说起了,首先,传输协议上:

  • RPC 是一种基于 TCP 传输层或者 HTTP2 应用层的通信协议;
  • HTTP 只基于 HTTP 协议,包括 HTTP1.x(即 HTTP1.0、1.1) 和 HTTP2,目前很多浏览器默认使用 1.x 来访问服务器数据。

性能消耗上(从数据类型对比):

  • RPC,可以基于 gRPC(一种 RPC 框架)实现高效的二进制传输;
  • HTTP,大部分是通过 json 来实现的,字节大小和序列化都比 gRPC 更消耗性能。

负载均衡上:

  • RPC,基本都自带了负载均衡策略;
  • HTTP,需要配置 Nginx,HAProxy 来实现。

传输效率上:

  • RPC,使用自定义的 TCP 协议,可以让请求报文体积更小,或者使用 HTTP2 协议,也可以很好的减少报文的体积,提高传输效率;
  • HTTP,如果是基于 HTTP1.x 的协议,请求中会包含很多无用的内容;如果是基于 HTTP2.0,那么简单的封装后是可以作为 RPC 来使用的,这时标准 RPC 框架更多的优势是服务治理。

综上对比,我们不难发现,RPC 从性能消耗和传输效率,以及负载均衡等方面都比 HTTP 强一些。这时细心的朋友可能已经发现了,那为啥我们常见的系统和网站都是用的 HTTP 协议,不改成 RPC 通信呢?

举个通俗的例子,HTTP 好比普通话,RPC 好比地方方言,比如粤语,西南一带的云南话、贵州话、四川话。

讲普通话,好处就是谁都听得懂,大部分国人都会讲,所以 HTTP 具有一定的通用性。讲方言,好处是可以更精简、更保密、更加可定制,坏处就是要求“说”方言的另一方(特指 client 端)也要懂,而且一旦大家都说一种方言了,换方言就困难了。所以 RPC 一般用于公司内部的服务调用,比如阿里巴巴的淘宝系统中的 A 服务和 B 服务之间。

 

流行的 RPC 框架

目前流行的 RPC 框架有很多,下面介绍常见的三种。
  1. gRPC:gRPC 是 Google 于 2015 年公布的开源项目,基于 HTTP2.0 协议,并支持常见的众多编程语言。其中 HTTP 2.0 协议是基于二进制的 HTTP 协议的升级版本,支持多路并发数据传输等特性。
  2. Thrift:Thrift 是 Facebook 开发的一个内部系统跨语言 RPC 框架,于 2007 年贡献给 Apache 基金,成为 Apache 众多开源项目之一。
  3. Dubbo:Dubbo 是阿里巴巴在 2011 年对外开源的一个 RPC 框架,在很多互联网公司和企业应用中广泛使用,提供了一系列协议和序列化框架,可插拔,但仅支持 Java 语言。

国外 RPC 评测上,基于各 RPC 框架的测试情况对比,从吞吐率、响应时间和稳定性上,gRPC 综合性能较好,也是国内很多公司在用的 RPC 框架。而且,gRPC 是由 go 语言实现的,随着微服务、云计算的普及,用 go 语言的公司和项目日益增多,所以 gRPC 也成了 go 语言内部系统通信的不二选择。

gRPC 基于 ProtoBuf(Protocol Buffer)序列化协议开发,它的原理是通过 IDL(Interface Definition[ˌdefɪˈnɪʃn] Language,接口描述语言)文件来定义服务接口的参数和返回值类型,然后通过代码生成工具生成服务端和客户端的模板代码。这样,我们只需要实现一个 IDL 文件和业务交互代码,就可以使用 gRPC 进行通信了。

 

Protobuf与gRPC

Protobuf 简介

Proto Buffer 协议(简称 protobuf,下文同)和 json、xml 一样,是一种数据序列化方式(序列化,就是把内存中一段数据转化成二进制的形式,然后进行网络传输或存储)。注:内存对象→文本文件→二进制

  • protobuf 是跨语言(服务端和客户端可以是不同的语言)、跨平台(服务端和客户端可以运行在不同的操作系统)的序列化协议(注:protobuf 文件描述的是各种语言的共性的东西,所以与语言无关。各种平台都实现了网络通信协议,可以接收数据包,所以平台无关);
  • 不仅限于 gRPC,protobuf 还可以用作其它场景的数据传输和存储;

不同于 json 和 xml ,protobuf 在使用时需要先定义 IDL(数据定义规则),其好处是传输时数据体积更小,传输速度更快。

gRPC 的传输协议用的是 protobuf,所以我们要先学会 protobuf 文件的编写规则。

 

4.2 Protobuf 定义数据结构

和 yaml、xml 文件类似,protobuf 文件也需要特定的格式编写,以下是 protobuf 文件的通用写法【gpt.proto】:

除了上述图片中的说明,protobuf 文件还有一些关键字段,比如 message 是 protobuf 协议中最基本类型,相当于 Java 里面的 class 对象,Go 里面的 struct 结构体。如上图所示,每个 message 里有一或多个字段及字段类型,相当于对象的参数和参数类型。