gRPC 是 Google 公司开发的一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。

gRPC 是一款 RPC 框架,那么先了解 RPC 是什么。

1 RPC

1.1 RPC 介绍

RPC(Remote Procedure Call)远程过程调用,是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议,简单的理解是一个节点请求另一个节点提供的服务。RPC 只是一套协议,基于这套协议规范来实现的框架都可以称为 RPC 框架,比较典型的有 Dubbo、Thrift 和 gRPC。

1.2 RPC 机制和实现过程

RPC 是远程过程调用的方式之一,涉及调用方和被调用方两个进程的交互。因为 RPC 提供类似于本地方法调用的形式,所以对于调用方来说,调用 RPC 方法和调用本地方法并没有明显区别。

比如,说某个程序需要读取某个文件的数据,开发人员会在代码中执行 read 系统调用来获取数据。

  • 当 read 方法属于本地调用时,read 函数由链接器从依赖库中提取出来,接着链接器会将它链接到该程序中。虽然 read 中执行了特殊的系统调用,但它本身依然是通过将参数压入堆栈的常规方式调用的,调用方并不知道 read 函数的具体实现和行为。

  • 当 read 方法实际是一个远程过程时(比如调用远程文件服务器提供的方法),调用方程序中需要引入 read 的接口定义,称为客户端存根(client-stub)。远程过程 read 的客户端存根与本地方法的 read 函数类似,都执行了本地函数调用。不同的是它底层实现上不是进行操作系统调用读取本地文件来提供数据,而是将参数打包成网络消息,并将此网络消息发送到远程服务器,交由远程服务执行对应的方法,在发送完调用请求后,客户端存根随即阻塞,直到收到服务器发回的响应消息为止。

下图展示了远程方法调用过程中的客户端和服务端各个阶段的操作。
微服务通信:gRPC 介绍 - 图1

  • 当客户端发送请求的网络消息到达服务器时,服务器上的网络服务将其传递给服务器存根(server-stub)。服务器存根与客户端存根一一对应,是远程方法在服务端的体现,用来将网络请求传递来的数据转换为本地过程调用。服务器存根一般处于阻塞状态,等待消息输入。


  • 当服务器存根收到网络消息后,服务器将方法参数从网络消息中提取出来,然后以常规方式调用服务器上对应的实现过程。从实现过程角度看,就好像是由客户端直接调用一样,参数和返回地址都位于调用堆栈中,一切都很正常。实现过程执行完相应的操作,随后用得到的结果设置到堆栈中的返回值,并根据返回地址执行方法结束操作。以 read 为例,实现过程读取本地文件数据后,将其填充到 read 函数返回值所指向的缓冲区。

  • read 过程调用完后,实现过程将控制权转移给服务器存根,它将结果(缓冲区的数据)打包为网络消息,最后通过网络响应将结果返回给客户端。网络响应发送结束后,服务器存根会再次进入阻塞状态,等待下一个输入的请求。

  • 客户端接收到网络消息后,客户操作系统会将该消息转发给对应的客户端存根,随后解除对客户进程的阻塞。客户端存根从阻塞状态恢复过来,将接收到的网络消息转换为调用结果,并将结果复制到客户端调用堆栈的返回结果中。当调用者在远程方法调用 read 执行完毕后重新获得控制权时,它唯一知道的是 read 返回值已经包含了所需的数据,但并不知道该 read 操作到底是在本地操作系统读取的文件数据,还是通过远程过程调用远端服务读取文件数据。

  • 总结下 RPC 执行步骤:

    1. 1. 调用客户端句柄,执行传递参数。<br /> 2. 调用本地系统内核发送网络消息。<br /> 3. 消息传递到远程主机,就是被调用的服务端。<br /> 4. 服务端句柄得到消息并解析消息。<br /> 5. 服务端执行被调用方法,并将执行完毕的结果返回给服务器句柄。<br /> 6. 服务器句柄返回结果,并调用远程系统内核。<br /> 7. 消息经过网络传递给客户端。<br /> 8. 客户端接受数据。

1.3 RPC 框架的组成

一个完整的 RPC 框架包含了服务注册发现、负载、容错、序列化、协议编码和网络传输等组件。不同的 RPC 框架包含的组件可能会有所不同,但是一定都包含 RPC 协议相关的组件,RPC 协议包括序列化、协议编解码器和网络传输栈,如下图所示:
微服务通信:gRPC 介绍 - 图2

1.4 RPC 和 HTTP 区别

RPC 和 HTTP都是微服务间通信较为常用的方案之一,其实RPC 和 HTTP 并不完全是同一个层次的概念,它们之间还是有所区别的。

  • RPC 是远程过程调用,其调用协议通常包括序列化协议和传输协议。序列化协议有基于纯文本的 XML 和 JSON、二进制编码的 Protobuf 和 Hessian。传输协议是指其底层网络传输所使用的协议,比如 TCP、HTTP。

  • 可以看出 HTTP 是 RPC 的传输协议的一个可选方案,比如说 gRPC 的网络传输协议就是 HTTP。HTTP 既可以和 RPC 一样作为服务间通信的解决方案,也可以作为 RPC 中通信层的传输协议(此时与之对比的是 TCP 协议)。

1.5 常见的 RPC 框架

目前流行的开源 RPC 框架还是比较多的,有阿里巴巴的 Dubbo、Google 的 gRPC、Facebook 的 Thrift 和 Twitter 的 Finagle 等。

  • Go RPC:Go 语言原生支持的 RPC 远程调用机制,简单便捷。
  • gRPC:Google 发布的开源 RPC 框架,是基于 HTTP 2.0 协议的,并支持众多常见的编程语言,它提供了强大的流式调用能力,目前已经成为最主流的 RPC 框架之一。
  • Thrift:Facebook 的开源 RPC 框架,主要是一个跨语言的服务开发框架,作为老牌开源 RPC 协议,以其高性能和稳定性成为众多开源项目提供数据的方案选项。

2. gRPC

2.1 gRPC 介绍

gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。

  • 目前提供 C、Java 和 Go 语言版本,分别是:grpc,grpc-java,grpc-go。
  • 其中 C 版本支持 C,C++,Node.js,Python,Ruby,Objective-C,PHP 和 C# 支持。

与许多 RPC 系统类似,gRPC 也是基于以下理念:首先定义服务,指定其能够被远程调用的方法,包括参数和返回类型,这里使用 Protocol Buffers 来定义服务。在服务端实现定义的服务接口,并运行一个 gRPC 服务器来处理客户端调用。
微服务通信:gRPC 介绍 - 图3

2.2 gRPC 特点

  • 语言无关,支持多种语言;
  • 基于 IDL 文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub;
  • 通信协议基于标准的 HTTP/2 设计,支持双向流、消息头压缩、单 TCP 的多路复用、服务端推送等特性,这些特性使得 gRPC 在移动端设备上更加省电和节省网络流量;
  • 序列化支持 PB(Protocol Buffer)和 JSON,PB 是一种语言无关的高性能序列化框架,基于 HTTP/2 + PB, 保障了 RPC 调用的高性能。

有了 gRPC, 我们可以一次性的在一个 .proto 文件中定义服务并使用任何支持它的语言去实现客户端
和服务器,反过来,它们可以在各种环境中,从 Google 的服务器到你自己的平板电脑—— gRPC 帮你解决了
不同语言及环境间通信的复杂性。

2.3 主要概念

2.3.1 服务定义

gRPC 基于如下思想:定义一个服务, 指定其可以被远程调用的方法及其参数和返回类型。gRPC 默认使用 protocol buffers 作为接口定义语言,来描述服务接口和有效载荷消息结构。如果有需要的话,可以使用其他替代方案。

  1. service HelloService {
  2. rpc SayHello (HelloRequest) returns (HelloResponse);
  3. }
  4. message HelloRequest {
  5. required string greeting = 1;
  6. }
  7. message HelloResponse {
  8. required string reply = 1;
  9. }

gRPC 允许你定义四类服务方法:

  • 单项 RPC,即客户端发送一个请求给服务端,从服务端获取一个应答,就像一次普通的函数调用。

    1. rpc SayHello(HelloRequest) returns (HelloResponse){
    2. }
  • 服务端流式 RPC,即客户端发送一个请求给服务端,可获取一个数据流用来读取一系列消息。客户端从返回的数据流里一直读取直到没有更多消息为止。

    1. rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
    2. }
  • 客户端流式 RPC,即客户端用提供的一个数据流写入并发送一系列消息给服务端。一旦客户端完成消息写入,就等待服务端读取这些消息并返回应答。

    1. rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
    2. }
  • 双向流式 RPC,即两边都可以分别通过一个读写数据流来发送一系列消息。这两个数据流操作是相互独立的,所以客户端和服务端能按其希望的任意顺序读写,例如:服务端可以在写应答前等待所有的客户端消息,或者它可以先读一个消息再写一个消息,或者是读写相结合的其他方式。每个数据流里消息的顺序会被保持。

    1. rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
    2. }

2.3.2 使用 API 接口

gRPC 提供 protocol buffer 编译插件,能够从一个服务定义的 .proto 文件生成客户端和服务端代码。通常 gRPC 用户可以在服务端实现这些 API,并从客户端调用它们。

  • 在服务侧,服务端实现服务接口,运行一个 gRPC 服务器来处理客户端调用。gRPC 底层架构会解码传入的请求,执行服务方法,编码服务应答。
  • 在客户侧,客户端有一个存根实现了服务端同样的方法。客户端可以在本地存根调用这些方法,用合适的 protocol buffer 消息类型封装这些参数— gRPC 来负责发送请求给服务端并返回服务端 protocol buffer 响应。

参考链接: https://www.cnblogs.com/songgj/p/13463717.html