一、什么是gRPC?
1.1 gRPC简介
gRPC和protocol buffers。
gRPC可以使用 protocol buffers作为其接口定义语言(IDL)和基础消息交换格式
1.1.1 概述
在gRPC中,客户端应用程序可以不同的机器上像调用本地方法一样,直接调用服务器应用程序上的方法,使得更容易创建分布式应用和服务。
gRPC是基于定义服务的思想,指定可以远程调用的方法及其参数和返回类型。在服务端,服务端实现此接口并运行gRPC服务器来处理客户端调用。在客户端,客户端有一个stub,提供与服务器相同的方法。
1)使用protocol buffers
默认情况下,gRPC使用protocol buffers,其是谷歌用于序列化结构化数据的开源框架
第一步:在一个proto 文件中定义你想要序列化的数据的结构
message Person {
string name = 1;
int32 id = 2;
bool has_ponycopter = 3;
}
第二步:使用protocol buffers编译器从proto文件中以首选语言生成数据访问类,这为每个字段提供了简单的访问器,以及将整个结构序列化/解析为原始字节的方法。
例如,如果选择的语言是C++,那么在上面的示例中运行编译器后,将生成一个可被调用的类。可以在应用程序中使用这个类来填充、序列化和检索protocol buffer message。
在普通的proto文件中定义gRPC服务,使用RPC方法参数和返回类型来作为protocol buffers的message:
#The greater service definition
service Greater {
//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;
}
1.2 核心概念
介绍gRPC的核心概念、架构和生命周期
1.2.1 概述
1)服务定义
与许多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 RPCs:客户端向服务端发送单个请求并获得单个响应,就像普通的函数调用
rpc SayHello(HelloRequest) returns (HelloResponse);
- Server Streaming RPCs:客户端向服务端发送请求并获得读取消息序列的流。客户端从返回的流中读取消息,直到没有更多的消息。gRPC保证了单个RPC调用中消息顺序。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
- Client Streming RPCs:客户端写入消息序列并将它们发送到服务器,同样使用提供的流。一旦客户端完成了消息的写入,它将等待服务器读取消息并返回其响应。gRPC再次保证了单个RPC调用中的消息顺序。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
- Bidirectional Streaming RPCs:双方使用读写流发送消息序列。这两个流独立运行,因此客户端和服务器可以按照自己喜欢的顺序进行读写:例如,服务器可以等待接收到所有客户端消息后再写入响应,或者它可以交替地读取消息然后写入消息,或者其他一些读写组合。保留了每个流中的消息顺序。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
2)使用API
从文件中的服务定义开始,gRPC提供协议缓冲区编译器插件来生成客户端和服务器端代码。gRPC用户通常在客户端调用这些API,并在服务器端实现相应的API
- 在服务器端,服务器实现服务声明的方法,并运行gRPC服务器来处理客户端调用。gRPC基础结构解码传入请求,执行服务方法,并编码服务响应。
- 在客户端,客户端有一个本地对象,称为Stub(对于某些语言,首选术语是客户端),它实现与服务相同的方法。然后,客户端可以在本地对象上调用这些方法,这些方法将调用的参数封装在适当的协议缓冲区消息类型中,将请求发送到服务器,并返回服务器的协议缓冲区响应。
3)RPC生命周期
深入了解当gRPC客户机调用gRPC服务器方法时会发生什么
1. Unary RPCs
a)一旦客户端调用了Stub方法,服务端就会收到RPC调用的通知,其中包括该调用的客户端元数据、方法名称和指定的截止日期
b)服务端可以直接发送回自己的初始元数据(在任何响应之前发送),或者等待客户端的请求消息。
c)一旦服务端获得了客户端的请求消息,他就会执行创建和填充响应所需的任何工作。然后将响应连同状态详细信息以及可选的尾部元数据一起返回给客户端
d)如果响应状态为OK,则客户端获得响应,完成客户端的调用
2. Server streaming RPCs
Server streaming RPC类似于Unary RPC,不同之处在于服务器在响应客户端的请求时返回消息流。发送完所有消息后,服务器的状态详细信息(状态码和可选状态消息)和可选的尾随元数据被发送到客户端。这就完成了服务器端的处理。客户端在拥有所有服务器消息后完成调用
3. Client streaming RPCs
Client streaming RPC类似于Unary RPC,不同之处是客户端向服务器发送消息流而不是单个消息。服务器用一条消息(连同它的状态详细信息和可选的尾随元数据)进行响应,通常是在它接收到所有客户机的消息之后,但不一定是这样。
4. Bidirectional streaming RPCs
在Bidirectional streaming RPC中,调用由调用方法的客户端和接收客户端元数据、方法名称和截止日期的服务器发起。服务器可以选择发回其初始元数据,或者等待客户端开始流式传输消息。
客户端和服务器端流处理是特定于应用程序的。由于这两个流是独立的,客户端和服务器可以以任何顺序读写消息。例如,服务器可以等到接收到客户端的所有消息后再写入消息,或者服务器和客户端可以玩“ping-pong”游戏——服务器收到请求,然后发回响应,然后客户端根据响应发送另一个请求,以此类推。
4)Deadline/Timeouts
gRPC允许客户端指定在RPC以错误终止之前他们愿意等待RPC完成的时间。在服务器端,服务器