概述
在 gRPC 中,客户端应用程序可以直接调用不同机器上的服务器应用程序上的方法,就像它是本地对象一样,使您可以更轻松地创建分布式应用程序和服务。与许多 RPC 系统一样,gRPC 基于定义服务的思想,指定可以通过参数和返回类型远程调用的方法。在服务器端,服务器实现了这个接口并运行一个 gRPC 服务器来处理客户端调用。在客户端,客户端有一个存根(在某些语言中简称为客户端),它提供与服务器相同的方法。
gRPC 客户端和服务器可以在各种环境中运行和相互通信 - 从 Google 内部的服务器到您自己的桌面 - 并且可以用任何 gRPC 支持的语言编写。因此,例如,您可以轻松地使用 Java、Go、Python 或 Ruby 中的客户端创建一个 gRPC 服务器。此外,最新的 Google API 将具有其接口的 gRPC 版本,让您可以轻松地将 Google 功能构建到您的应用程序中。
使用协议缓冲区
默认情况下,gRPC 使用协议缓冲区,谷歌成熟的用于结构化数据序列化的开源机制(虽然它可以与其他数据格式如JSON一起使用)。这是它如何工作的快速介绍。如果您已经熟悉协议缓冲区,请随时跳到下一节。
使用协议缓冲区的第一步是定义要在proto 文件中序列化的数据的结构:这是一个带有.proto
扩展名的普通文本文件。协议缓冲区数据被构造为 消息,其中每条消息都是一个小的信息逻辑记录,包含一系列称为字段的名称-值对。这是一个简单的例子:
message Person {
string name = 1;
int32 id = 2;
bool has_ponycopter = 3;
}
然后,一旦指定了数据结构,就可以使用协议缓冲区编译器protoc
从原型定义中生成首选语言的数据访问类。这些为每个字段提供了简单的访问器,如name()
和set_name()
,以及将整个结构序列化/解析为原始字节/从原始字节序列化/解析整个结构的方法。因此,例如,如果您选择的语言是 C++,则在上面的示例中运行编译器将生成一个名为Person
. 然后,您可以在应用程序中使用此类来填充、序列化和检索Person
协议缓冲区消息。
您在普通的 proto 文件中定义 gRPC 服务,将 RPC 方法参数和返回类型指定为协议缓冲区消息:
// The greeter service definition. service Greeter {
// Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name. message HelloRequest {
string name = 1;
}
// The response message containing the greetings message HelloReply {
string message = 1;
}
gRPC 使用protoc
特殊的 gRPC 插件从您的 proto 文件生成代码:您将获得生成的 gRPC 客户端和服务器代码,以及用于填充、序列化和检索消息类型的常规协议缓冲区代码。
核心概念、架构和生命周期
对关键 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 基础设施解码传入请求、执行服务方法并编码服务响应。
- 在客户端,客户端有一个称为stub(对于某些语言,首选术语是client)的本地对象,它实现与服务相同的方法。然后客户端可以在本地对象上调用这些方法,将调用的参数包装在适当的协议缓冲区消息类型中 - gRPC 负责将请求发送到服务器并返回服务器的协议缓冲区响应。
同步与异步
在服务器响应到达之前阻塞的同步 RPC 调用最接近于 RPC 所追求的过程调用的抽象。另一方面,网络本质上是异步的,在许多情况下,能够在不阻塞当前线程的情况下启动 RPC 很有用。
大多数语言中的 gRPC 编程 API 都有同步和异步两种风格。您可以在每种语言的教程和参考文档中找到更多信息(完整的参考文档即将推出)。
RPC 生命周期
在本节中,您将仔细了解当 gRPC 客户端调用 gRPC 服务器方法时会发生什么。有关完整的实现详细信息,请参阅特定于语言的页面。
一元RPC
首先考虑客户端发送单个请求并返回单个响应的最简单的 RPC 类型。
- 一旦客户端调用了存根方法,服务器就会收到通知:RPC 已经被调用,其中包含客户端的元数据 、方法名称和指定的截止日期(如果适用)。
- 然后服务器可以立即发回它自己的初始元数据(必须在任何响应之前发送),或者等待客户端的请求消息。首先发生的是特定于应用程序的。
- 一旦服务器收到客户端的请求消息,它就会执行创建和填充响应所需的任何工作。然后将响应(如果成功)连同状态详细信息(状态代码和可选状态消息)和可选的尾随元数据一起返回给客户端。
- 如果响应状态为OK,则客户端得到响应,在客户端完成调用。
服务器流式RPC
服务器流式 RPC 类似于一元 RPC,不同之处在于服务器返回消息流以响应客户端的请求。发送完所有消息后,服务器的状态详细信息(状态代码和可选状态消息)和可选的尾随元数据将发送到客户端。这样就完成了服务器端的处理。一旦客户端拥有服务器的所有消息,它就完成了。
客户端流式 RPC
客户端流式 RPC 类似于一元 RPC,不同之处在于客户端向服务器发送消息流而不是单个消息。服务器用一条消息(连同它的状态详细信息和可选的尾随元数据)进行响应,通常但不一定是在它收到所有客户端的消息之后。
双向流式RPC
在双向流式 RPC 中,调用由调用方法的客户端和接收客户端元数据、方法名称和截止日期的服务器发起。服务器可以选择发回其初始元数据或等待客户端开始流式传输消息。
客户端和服务器端流处理是特定于应用程序的。由于两个流是独立的,客户端和服务器可以按任意顺序读写消息。例如,服务器可以等到收到所有客户端的消息后再写入消息,或者服务器和客户端可以玩“乒乓”——服务器收到请求,然后发回响应,然后客户端发送基于响应的另一个请求,依此类推。
截止日期/超时
gRPC 允许客户端指定在 RPC 因DEADLINE_EXCEEDED
错误终止之前他们愿意等待 RPC 完成多长时间。在服务器端,服务器可以查询特定的 RPC 是否超时,或者还剩下多少时间来完成 RPC。
指定截止日期或超时是特定于语言的:某些语言 API 根据超时(时间持续时间)工作,而某些语言 API 根据截止日期(固定时间点)工作,并且可能有也可能没有默认截止日期。
RPC 终止
在 gRPC 中,客户端和服务器都对调用的成功做出独立和本地的判断,它们的结论可能不一致。这意味着,例如,您可能有一个 RPC 在服务器端成功完成(“我已经发送了我所有的响应!”)但在客户端失败(“响应在我的截止日期之后到达!”)。服务器也有可能在客户端发送其所有请求之前决定完成。
取消 RPC
客户端或服务器都可以随时取消 RPC。取消会立即终止 RPC,以便不再进行进一步的工作。
警告
取消之前所做的更改不会回滚。
元数据
元数据是键值对列表形式的特定 RPC 调用的信息(例如身份验证详细信息),其中键是字符串,值通常是字符串,但也可以是二进制数据。元数据对 gRPC 本身是不透明的——它允许客户端提供与服务器调用相关的信息,反之亦然。
对元数据的访问取决于语言。
频道
gRPC 通道提供到指定主机和端口上的 gRPC 服务器的连接。它在创建客户端存根时使用。客户端可以指定通道参数来修改 gRPC 的默认行为,例如打开或关闭消息压缩。通道具有状态,包括connected
和idle
。
gRPC 如何处理关闭通道取决于语言。某些语言还允许查询通道状态。