gRPC

gRPC

gRPC 是由 Google 开源的 Bi-directional Streaming RPC 框架,其内置了高性能的二进制编码,相较于 JSON 与 HTTP 其有更好的压缩率。gRPC 最早由 Google 与 Square 合作构建,是 Stubby,ARCWire 和 Sake 的替代品。gRPC 框架是基于 IDL(接口描述语言)的 Actor 模型的一种形式,它是通过 Protocol Buffers 消息格式定义的。随着 HTTP/2 的引入,内部的 Google Stubby 和 Square Sake 框架现已向公众开放。通过在 HTTP/2 协议之上工作,gRPC 使消息可以作为提示流双向复用和压缩,以最大化任何微服务生态系统的容量。gRPC 为使用同步和异步通信的可伸缩双向流提供了一个平台。

gRPC allows for asynchronous language-agnostic message passing via Protocol Buffers.

在一般的 RPC 机制中,客户端启动与服务器的连接,只有客户端可以请求,而服务器只能响应传入的请求。但是,在双向 gRPC 流中,尽管初始连接是由客户端(称为端点 1)发起的,但是一旦建立连接,服务器(称为端点 2)和端点 1 都可以发送请求和接收响应 。这极大地简化了两个端点之间相互通信(例如网格计算)的开发。由于两个流都是独立的,因此也省去了在端点之间创建两个独立连接的麻烦(一个从端点 1 到端点 2,另一个从端点 2 到端点 1)。gRPC 使用标头压缩在单个连接上多路复用请求。这使得 gRPC 可以用于电池寿命和数据使用很重要的移动客户端。核心库使用 C 语言(Java 和 Go 除外),并且通过该库连接的所有其他语言都实现了表面 API(Google,n.d。)。

由于 Protocol Buffers 已被许多个人和公司使用,因此 gRPC 使其自然可以通过 gRPC 扩展其 RPC 生态系统。像 Cisco,Juniper 和 Netflix 等公司发现采用它很实用。大部分 Google Public API(例如其地标和地图 API)也已移植到 gRPC ProtoBuf。

HTTP/2

HTTP 1.1 协议已经取得了一定的成功,但是随着分布式计算的增加,特别是在微服务领域,社区开始要求一些关键功能。创建基于无共享模型,具有双向,高吞吐量请求和响应方法的有机构建的更多模块化功能单元的现象,需要一种新的通信和集成协议。因此,HTTP/2 诞生了一个新的标准,它是一种二进制线路协议,提供了可以并发复用的压缩流。由于许多微服务实现当前在实际处理任何有效负载之前会扫描标头消息,以便扩大消息的处理和路由,因此 HTTP/2 为此提供了头压缩。最后一个重要好处是服务器端点可以根据预期的未来通信实际将缓存的资源推送到客户端,从而大大节省了客户端的通信时间和处理量。

HTTP/2 Frames

HTTP/2 协议现在是一种框架协议,它扩展了双向异步通信的功能。因此,每个消息都是帧的一部分,除了要处理的标准帧长以外,还将具有头,帧类型和流标识符。每个流可以具有优先级,这允许形成优先级树的流之间实现依赖性。数据可以是允许双向通信的请求或响应,具有标记通信以终止流,具有优先级设置的流控制,来自服务器的继续和推送响应以进行客户端确认的功能。以下是 HTTP/2 帧的格式:

The encoding a HTTP/2 frame.

Header Compression

HTTP 头是传递有关其他端点状态,请求或响应以及有效负载的信息的主要方法之一。这使端点能够在处理大量流时节省时间,并且能够转发信息,而不会浪费时间检查有效负载。由于头信息可能非常大,因此现在可以对其进行压缩,以实现更好的吞吐量和所存储状态信息的容量。

Multiplexed Streams

由于流是 HTTP/2 实现的核心,因此重要的是讨论协议中其实现的细节。由于可以从许多端点同时打开许多流,因此每个流将处于以下状态之一。每个流被多路复用在一起,形成一串通过有线传输的流,从而允许接收端点执行异步双向并发。以下是流的生命周期:

The lifecycle of a HTTP/2 stream.

为了更好地理解该图,在其中定义一些术语很重要:

  • PUSH_PROMISE - This is being performed by one endpoint to alert another that it will be sending some data over the wire.

  • RST_STREAM - This makes termination of a stream possible.

  • PRIORITY - This is sent by an endpoint on the priority of a stream.

  • END_STREAM - This flag denotes the end of a DATA frame.

  • HEADERS - This frame will open a stream.

  • Idle - This is a state that a stream can be in when it is opened by receiving a HEADERS frame.

  • Reserved (Local) - To be in this state is means that one has sent a PUSH_PROMISE frame.

  • Reserved (Remote) - To be in this state is means that it has been reserved by a remote endpoint.

  • Open - To be in this state means that both endpoints can send frames.

  • Closed - This is a terminal state.

  • Half-Closed (Local) - This means that no frames can be sent except for WINDOW_UPDATE, PRIORITY, and RST_STREAM.

  • Half-Closed (Remote) - This means that a frame is not used by the remote endpoint to send frames of data.

Flow Control of Streams

由于许多流将争夺连接带宽,因此可以防止传输中的瓶颈和冲突。这是通过 WINDOW_UPDATE 有效负载为每个流以及整个连接完成的,以使发送方知道接收端点有多少空间来处理新数据。

Protocol Buffers

尽管 gRPC 是在 HTTP/2 之上构建的,但必须使用 IDL 来执行端点之间的通信。使用 Protocol Buffers 的自然方向是为服务器和客户端之间的序列化构造基于键值的数据的方法。在开始 gRPC 开发时,仅提供 2.0 版(proto2),该版本仅实现了数据结构,而没有任何请求/响应机制。Protocol Buffers 数据结构的示例如下所示:

// A message containing the user's name.
message Hello {
  string name = 1;
}

通过有线发送时,此消息也将被编码以获得最高压缩率。例如,假设消息是字符串“ Hi”。每个 Protocol Buffers 类型都有一个值,在这种情况下,字符串的值为 2,如下表所示。

Tag values for Protocol Buffer types.

将会注意到,Protocol Buffers 定义中的每个字段元素都有一个数字,代表它的标签。在图 3 中,字段名称的标签为 1。当对消息进行编码时,每个字段(键)都将以一个字节值(8 位)开头,其中最低有效的 3 位值将对类型进行编码,其余的将进行编码。标签。在这种情况下,标记为 1,类型为 2。因此,编码将为 00001 010,其十六进制值为 A。下一个字节是字符串的长度,即 2,其后是字符串 48 和 69 代表 H 和 i。因此,整个传输将如下所示:

A 2 48 69

因此,必须更新语言以支持 gRPC,并为 Protocol Buffers 的 3.0.0 版添加带有请求和响应定义的服务消息。更新后的实现如下所示:

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

请注意,增加了一项服务,其中 RPC 调用将使用一条消息作为请求的结构,而另一条消息为响应消息格式。一旦生成了这些 Proto 文件,便可以使用它们与 gRPC 进行编译,以生成表示 RPC 实现的经典两个端点的 Client 和 Server 文件。