核心概念、架构和生命周期

gRPC 关键概念介绍,以及 gRPC 架构和 RPC 生命周期概述。

核心概念、架构和生命周期

gRPC 关键概念介绍,以及 gRPC 架构和 RPC 生命周期概述。

不熟悉 gRPC?请先阅读 gRPC 简介。有关特定语言的详细信息,请参阅您所选语言的快速入门、教程和参考文档。

概述

服务定义

与许多 RPC 系统类似,gRPC 基于定义服务的理念,指定可远程调用的方法及其参数和返回类型。默认情况下,gRPC 使用 Protocol Buffers 作为接口定义语言 (IDL),用于描述服务接口和负载消息的结构。如果需要,也可以使用其他替代方案。

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string greeting = 1;
}

message HelloResponse {
  string reply = 1;
}

gRPC 允许您定义四种服务方法:

  • 一元 RPC,客户端向服务器发送单个请求并获得单个响应,就像一个普通的函数调用。

    rpc SayHello(HelloRequest) returns (HelloResponse);
    
  • 服务器流式 RPC,客户端向服务器发送请求并获得一个流,用于读取一系列返回的消息。客户端从返回的流中读取,直到没有更多消息。gRPC 保证单个 RPC 调用中的消息顺序。

    rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
    
  • 客户端流式 RPC,客户端写入一系列消息并将其发送到服务器,同样使用提供的流。一旦客户端完成消息写入,它就会等待服务器读取这些消息并返回其响应。同样,gRPC 保证单个 RPC 调用中的消息顺序。

    rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
    
  • 双向流式 RPC,双方使用读写流发送一系列消息。两个流独立运行,因此客户端和服务器可以以任何顺序读写:例如,服务器可以等待接收所有客户端消息后再写入其响应,或者它可以交替读取消息然后写入消息,或者读写的其他组合。每个流中的消息顺序都得到保留。

    rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
    

您将在下面的 RPC 生命周期 部分了解更多关于不同类型 RPC 的信息。

使用 API

从 `.proto` 文件中的服务定义开始,gRPC 提供 Protocol Buffers 编译器插件,用于生成客户端和服务器端代码。gRPC 用户通常在客户端调用这些 API,并在服务器端实现相应的 API。

  • 在服务器端,服务器实现服务声明的方法,并运行 gRPC 服务器来处理客户端调用。gRPC 基础设施解码传入的请求,执行服务方法,并编码服务响应。
  • 在客户端,客户端有一个称为 存根(对于某些语言,首选术语是 客户端)的本地对象,它实现与服务相同的方法。客户端可以直接在本地对象上调用这些方法,这些方法会将调用参数封装成相应的 Protocol Buffers 消息类型,发送请求到服务器,并返回服务器的 Protocol Buffers 响应。

同步与异步

同步 RPC 调用会阻塞直到服务器响应到达,它们最接近 RPC 所追求的过程调用抽象。另一方面,网络本质上是异步的,在许多场景中,能够在不阻塞当前线程的情况下启动 RPC 是很有用的。

大多数语言的 gRPC 编程 API 都提供同步和异步两种形式。您可以在每种语言的教程和参考文档中找到更多信息(完整的参考文档即将推出)。

RPC 生命周期

在本节中,您将仔细了解 gRPC 客户端调用 gRPC 服务器方法时会发生什么。有关完整的实现细节,请参阅特定语言页面。

一元 RPC

首先考虑最简单的 RPC 类型:客户端发送单个请求并获得单个响应。

  1. 一旦客户端调用存根方法,服务器会收到通知,表明 RPC 已被调用,并带有客户端的此调用 元数据、方法名称以及适用的指定 截止时间
  2. 服务器随后可以立即发送回自己的初始元数据(必须在任何响应之前发送),或者等待客户端的请求消息。哪个先发生,取决于应用程序。
  3. 一旦服务器收到客户端的请求消息,它会执行必要的工作来创建并填充响应。然后,响应(如果成功)与状态详情(状态码和可选状态消息)以及可选的尾随元数据一起返回给客户端。
  4. 如果响应状态为 OK,则客户端收到响应,从而在客户端完成调用。

服务器流式 RPC

服务器流式 RPC 类似于一元 RPC,不同之处在于服务器响应客户端请求时返回的是消息流。发送完所有消息后,服务器的状态详情(状态码和可选状态消息)和可选的尾随元数据会发送给客户端。这表示服务器端处理完成。客户端在收到所有服务器消息后完成。

客户端流式 RPC

客户端流式 RPC 类似于一元 RPC,不同之处在于客户端向服务器发送的是消息流而不是单个消息。服务器会返回单个消息(连同其状态详情和可选的尾随元数据),通常(但不一定)在收到所有客户端消息之后。

双向流式 RPC

在双向流式 RPC 中,调用由客户端调用方法发起,服务器接收客户端元数据、方法名称和截止时间。服务器可以选择发送其初始元数据,或者等待客户端开始流式传输消息。

客户端和服务器端流处理是特定于应用程序的。由于两个流是独立的,客户端和服务器可以以任何顺序读写消息。例如,服务器可以等到收到客户端的所有消息后再写入其消息,或者服务器和客户端可以“玩乒乓球”——服务器收到请求,然后发送响应,然后客户端根据响应发送另一个请求,依此类推。

截止时间/超时

gRPC 允许客户端指定他们愿意等待 RPC 完成多长时间,在此时间之后 RPC 将因 DEADLINE_EXCEEDED 错误而终止。在服务器端,服务器可以查询特定 RPC 是否已超时,或完成该 RPC 还有多少时间。

指定截止时间或超时是特定于语言的:一些语言 API 以超时(时间持续)的方式工作,而另一些语言 API 以截止时间(固定的时间点)的方式工作,并且可能有或没有默认截止时间。

RPC 终止

在 gRPC 中,客户端和服务器都对调用的成功进行独立和本地判断,它们的结论可能不匹配。这意味着,例如,一个 RPC 可能在服务器端成功完成(“我已发送所有响应!”),但在客户端失败(“响应在我设定的截止时间之后才到达!”)。服务器也可能决定在客户端发送所有请求之前完成。

取消 RPC

客户端或服务器可以随时取消 RPC。取消会立即终止 RPC,以便不再进行任何进一步的工作。

元数据

元数据是关于特定 RPC 调用的信息(例如 身份验证详情),其形式为键值对列表,其中键是字符串,值通常是字符串,但也可以是二进制数据。

键不区分大小写,由 ASCII 字母、数字和特殊字符 -_. 组成,且不得以 grpc- 开头(此部分保留给 gRPC 自身使用)。二进制值键以 -bin 结尾,而 ASCII 值键则不以 -bin 结尾。

用户定义的元数据不被 gRPC 使用,它允许客户端向服务器提供与调用相关的信息,反之亦然。

元数据的访问是语言相关的。

通道

gRPC 通道提供与指定主机和端口上的 gRPC 服务器的连接。它在创建客户端存根时使用。客户端可以指定通道参数来修改 gRPC 的默认行为,例如打开或关闭消息压缩。通道具有状态,包括 connected(已连接)和 idle(空闲)。

gRPC 处理关闭通道的方式是语言相关的。一些语言也允许查询通道状态。

最后修改于 2024 年 11 月 12 日:在不同网页中嵌入 YouTube 视频 (#1380) (196f408)