gRPC 核心概念、架构和生命周期
gRPC 核心概念、架构和生命周期
介绍 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 允许您定义四种服务方法:
- 一元(Unary) RPC,客户端向服务器发送单个请求,并返回单个响应,就像普通函数调用一样。
rpc SayHello(HelloRequest) returns (HelloResponse);
- 服务器流式(Server streaming) RPC,其中客户端向服务器发送请求并获取流以读回一系列消息。客户端读取返回的流,直到不再有 messages。gRPC 保证单个 RPC 调用中的消息排序。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
- 客户端流式(Client streaming) RPC,其中客户端写入一系列消息并再次使用提供的流将其发送到服务器。一旦客户端完成了消息的编写,它将等待服务器读取消息并返回其响应。gRPC 再次保证单个 RPC 调用中的消息排序。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
- 双向流式(Bidirectional streaming) RPC,其中双方使用读写流发送消息序列。这两个流独立运行,因此客户机和服务器可以按照他们喜欢的顺序进行读写:例如,服务器可以等待接收所有客户机消息,然后再写入响应,或者它可以交替地读消息,然后写消息,或者读写的其他组合。保留每个流中消息的顺序。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
您将在下面的 RPC 生命周期
部分中了解有关不同类型的RPC的更多信息。
使用API
从 .proto
文件中的 service definition 开始,gRPC 提供生成 client- and server-side 端代码的 protocol buffer 编译器插件。gRPC 用户通常在客户端调用这些 API,并在服务器端实现相应的 API。
- 在 server 端,server 实现服务声明的方法,并运行 gRPC 服务器来处理 client 调用。gRPC 基础设施对传入请求进行解码,执行 service 方法,并对 service 响应进行编码。
- 在 client 端,client 有一个称为 stub 本地对象(对于某些语言,首选术语是 client),它实现了与服务相同的方法。然后,client 可以在本地对象上调用这些方法,将调用的参数包装在适当的 protocol buffer 消息类型中-gRPC 负责将请求发送到 server 并返回 server’s protocol buffer 响应.
同步与异步
Synchronous RPC 调用在 server 响应到达之前阻塞,这与 RPC 所期望的过程调用的抽象最接近。另一方面,网络本身是 asynchronous 的,在许多情况下,能够在不阻塞当前线程的情况下启动 RPC 非常有用。
大多数语言中的gRPC编程API都有 synchronous 和 asynchronous 两种风格。您可以在每种语言的教程和参考文档中找到更多信息(完整的参考文档即将发布)。
RPC 生命周期
在本节中,您将更详细地了解 gRPC client 调用 gRPC server 方法时发生的情况。有关完整实现的详细信息,请参阅特定于语言的页面。
Unary RPC
首先考虑最简单的 RPC 类型,其中客户端发送单个请求并返回单个响应。
- 一旦 client 调用 stub 方法,server 就会收到通知,通知 RPC 已被调用,其中包含client 的 metadata 、方法名称和指定的 deadline(如果适用)。
- 然后,server 可以立即发送回自己的初始 metadata(必须在任何响应之前发送),或者等待 client 的请求消息。首先发生的是特定于应用的。
- 一旦 server 收到 client 的请求消息,它将执行创建和填充响应所需的任何工作。然后将响应(如果成功)连同状态详细信息(status code 和可选的状态 message)和可选的跟踪 metadata 一起返回给客户端。
- 如果响应状态为 OK,则 client 将获得响应,从而在 client 完成调用。
Server streaming RPC
server-streaming RPC 类似于 unary RPC,只是 server 返回一个响应 client 请求的消息流。发送所有消息后,server 的状态详细信息(status code 和可选状态 message)和可选的跟踪 metadata 将发送到 client。这就完成了 server 的处理。一旦 client 拥有 server 的所有消息,它就完成了。
Client streaming RPC
client-streaming RPC 类似于 unary RPC,除了 client 向服务器发送消息流而不是单个消息。server 用一条消息(连同状态详细信息和可选的尾部 metadata)进行响应,通常但不一定是在接收到所有 client 消息之后。
Bidirectional streaming RPC
在 bidirectional streamingRPC 中,调用由调用方法的 client 和接收 client metadata、方法名称和截止日期的 server 发起。server 可以选择发回其初始 metadata 或等待 client 开始流式传输消息。
client 和 server 流处理是特定于应用程序的。由于这两个流是独立的,client 和 server 可以按任何顺序读写消息。例如,server 可以等到收到 client 的所有消息后再编写消息,或者 server 和 client 可以玩“ping-pong”——server 收到请求,然后发送回响应,然后 client 根据响应发送另一个请求,以此类推。
Deadlines/Timeouts
gRPC 允许 client 指定他们愿意等待 RPC 完成多长时间,然后 RPC 以 DEADLINE_EXCEEDED
错误终止。在 server 可以查询特定 RPC 是否已超时,或者还有多少时间来完成 RPC。
指定截止日期或超时是特定于语言的:一些语言 API 根据超时(持续时间)工作
RPC termination
在 gRPC 中,client 和 server 对呼叫的成功做出独立的本地决定,并且它们的结论可能不匹配。这意味着,例如,您可以有一个在 server 成功完成的 RPC(“我已经发送了所有响应!”)但在 client 失败(“响应在我的截止日期之后到达!”)。server 也可以在 client 发送所有请求之前决定完成
Cancelling an RPC
client 或 server 可以随时取消 RPC。取消将立即终止 RPC,因此不再进行进一步的工作。
警告
取消前所做的更改不会回滚。
Metadata
Metadata 是关于特定 RPC 调用的信息(如 身份验证详细信息),以键-值对列表的形式,其中键是字符串,值通常是字符串,但可以是二进制数据。
密钥不区分大小写,由 ASCII 字母、数字和特殊字符 -
, _
, .
组成,并且不能以 grpc-
开头(这是为 grpc 本身保留的)。二进制值键以 -bin
结尾,而 ASCII 值键不以这个结尾。
Metadata 对 gRPC 本身是不透明的-它允许 client 向 server 提供与调用相关的信息,反之亦然。
Metadata 的访问取决于语言。
Channels
gRPC channel 提供与指定主机和端口上的 gRPC 服务器的连接。在创建 client stub 时使用。client 可以指定 channel 参数来修改 gRPC 的默认行为,例如打开或关闭消息压缩。通道有状态,包括 connected
和 idle
。
gRPC 如何关闭 channel 取决于语言。某些语言还允许查询 channel 状态。