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

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

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

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

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

概述

服务定义

与许多 RPC 系统一样,gRPC 基于定义服务的思想,指定可以通过参数和返回类型远程调用的方法。默认情况下,gRPC 使用 协议缓冲区 作为接口定义语言 (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 提供协议缓冲区编译器插件,生成客户端和服务器端代码。gRPC 用户通常在客户端调用这些 API,并在服务器端实现相应的 API。

  • 在服务器端,服务器实现服务声明的方法并运行 gRPC 服务器来处理客户端调用。gRPC 基础架构解码传入的请求,执行服务方法,并编码服务响应。
  • 在客户端,客户端有一个本地对象,称为存根(对于某些语言,首选术语是客户端),它实现与服务相同的方法。然后,客户端可以在本地对象上调用这些方法,并且这些方法将调用的参数包装在适当的协议缓冲区消息类型中,将请求发送到服务器,并返回服务器的协议缓冲区响应。

同步与异步

同步 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 值键则没有。

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

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

通道

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

gRPC 如何处理关闭通道是与语言相关的。某些语言还允许查询通道状态。

上次修改时间:2024 年 11 月 12 日: 在不同的网页中嵌入 YouTube 视频 (#1380) (196f408)