Service definition
与许多RPC系统一样,gRPC基于定义服务的思想,指定可以被远程调用的方法、参数、返回类型。默认情况下,gRPC使用 protocol buffer 作为接口定义语言(IDL)来描述服务接口和有效负载消息的结构。如果需要,可以使用其它替代(如JSON)。
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);
Using the API
从 .proto文件 中的服务定义开始,gRPC 提供 protocol buffer 编译器插件,用于生成客户端和服务器端代码。gRPC用户通常在 客户端调用这些API,并在 服务器端实现相应的API。
在服务端,服务器实现服务中声明的方法,运行一个 gRPC 服务器去处理客户端请求。gRPC 的基础设施对到来的请求解码,执行服务方法,对响应进行编码。
在客户端,客户端有一个称为 stub 的本地对象,它实现与服务相同的方法。然后,客户机就可以在本地对象上调用这些方法,将调用的参数包装在适当的 protocol buffer 消息类型中—gRPC将请求发送到服务器并返回服务器的protocol buffer 响应后进行处理。
Synchronous vs. asynchronous
同步RPC调用,在收到服务器响应之前一直阻塞,这与RPC所期望的过程调用的抽象最接近。另一方面,网络本身是异步的,在许多情况下,能够在不阻塞当前线程的情况下启动rpc是很有用的。
大多数语言中的 gRPC编程API 都有 同步 和 异步 两种风格。您可以在每种语言的教程和参考文档中找到更多信息。
RPC life cycle
在本节中,您将更详细地了解当 gRPC客户机调用 gRPC服务器方法时会发生什么。有关完整的实现详细信息,请参阅特定于语言的文档。
Unary PRC
首先考虑最简单的RPC类型,其中客户端发送单个请求并返回单个响应。
一旦客户机调用一个存根方法,就会通知服务器已经用客户机的元数据、方法名称和指定的截止日期(如果适用)调用了RPC。
然后,服务器可以直接发回自己的初始元数据(必须在任何响应之前发送),或者等待客户机的请求消息。首先发生的是特定于应用程序的。
一旦服务器收到客户机的请求消息,它就会执行创建和填充响应所需的任何工作。然后将响应(如果成功)连同状态详细信息(状态代码和可选状态消息)和可选的尾部元数据一起返回给客户机。
如果响应状态为OK,那么客户端将获得响应,从而完成客户端的调用。
Server streaming RPC
服务器流RPC类似于一元RPC,只是服务器响应客户机的请求返回消息流。发送所有消息后,服务器的状态详细信息(状态代码和可选的状态消息)和可选的尾部元数据将发送到客户端。这就完成了服务器端的处理。一旦客户端拥有了服务器的所有消息,它就完成了。
Client streaming RPC
客户端流式RPC与一元RPC类似,只是客户端向服务器发送消息流而不是单个消息。服务器通常(但不一定)在接收到客户机的所有消息之后,会用一条消息(连同其状态详细信息和可选的尾随元数据)进行响应。
Bidirectional streaming RPC
在双向流RPC中,调用由调用方法的客户端发起,服务端接收客户端元数据、方法名称和截止日期。服务器可以选择发回其初始元数据或等待客户端开始流式传输消息。
客户端和服务器端流处理是特定于应用程序的。由于这两个流是独立的,客户机和服务器可以按任何顺序读写消息。例如,服务器可以等到收到客户机的所有消息后再写入其消息,或者 服务器收到一个请求,然后发回一个响应,然后客户机根据响应发送另一个请求,依此类推。
Deadlines/Timeouts
gRPC允许客户端指定 在RPC因 DEADLINE_EXCEEDED 错误而终止之前,他们愿意等待RPC完成的时间。在服务器端,服务器可以查询特定的RPC是否超时,或者还剩余多少时间用于完成RPC。
指定 deadline 或 timeout 是特定于语言的:一些语言 APIs 根据 timeouts(durations of time)工作,而一些语言 APIs 根据 deadline(a fixed point in time)工作,可能有也可能没有默认的截止时间。
RPC termination
在gRPC中,客户端和服务器都各自对调用成功进行确定,其结论可能不匹配。这意味着,例如,您可能拥有一个在服务器端成功完成的RPC(“我已发送所有响应!”),而在客户端却失败了(“响应在我的截止日期之后到达!”)。服务器还可以在客户端发送所有请求之前决定完成。
Cancelling an RPC
客户机或服务器可以随时取消RPC。取消操作会立即终止RPC,以便不再进行进一步的工作。
注意:取消前所做的更改不会回滚。
Metadata
Metadata 是以 键值对列表 的形式表示的关于特定RPC调用的信息(例如身份验证详细信息),其中键是字符串,值通常是字符串,但可以是二进制数据。元数据对gRPC本身是不透明的-它允许客户端 向 服务器提供与调用相关的信息,反之亦然。
对 Metadata的访问依赖于 语言。
Channels
gRPC通道 提供到 指定主机和端口上的gRPC服务器的连接。它用于创建客户端存根。客户机可以指定通道参数来修改gRPC的默认行为,例如打开或关闭消息压缩。通道具有状态,包括已连接( connected )和 空闲( idle )。
gRPC如何处理 关闭通道 的问题取决于语言。有些语言还允许查询通道状态。