服务
最后,我们需要了解并将在本书中使用的一个重要构造是 服务(service)。在 Protobuf
中,服务是一个包含多个 RPC(远程过程调用)端点的集合,包含两个主要部分。第一部分是 RPC 的输入,第二部分是输出。因此,如果我们想为我们的账户系统定义一个服务,我们可以像以下这样进行定义:
message GetAccountRequest { … }
message GetAccountResponse { … }
service AccountService {
rpc GetAccount(GetAccountRequest) returns (GetAccountResponse);
// ...
}
在这里,我们定义了一个表示请求的消息(GetAccountRequest
),以及另一个表示响应的消息(GetAccountResponse
),并将它们作为 GetAccount
RPC 调用的输入和输出。在下一章,我们将讨论服务的更高级用法,但现在要理解的重要概念是:Protobuf
定义了服务,但并不会为它们生成代码,只有 gRPC 才会生成代码。
Protobuf
的服务用于描述合同,而由 RPC 框架来履行这个合同(在客户端和服务器端)。请注意,我提到的是 RPC 框架,而不仅仅是 gRPC。任何 RPC 框架都可以读取 Protobuf
服务提供的信息,并基于它生成代码。Protobuf
的目标是独立于任何语言和框架,它并不关心应用程序如何处理序列化后的数据。
最后,这些服务是 gRPC 的核心。正如我们将在本书中看到的那样,我们将使用它们来发起请求,并在服务器端实现它们以返回响应。在客户端使用定义好的服务时,我们会感觉像是在直接调用服务器上的函数。例如,假设我们有 AccountService
,我们可以通过以下代码调用 GetAccount
:
res := client.GetAccount(req)
在这里,client
是一个 gRPC 客户端的实例,req
是 GetAccountRequest
的实例,res
是 GetAccountResponse
的实例。在这种情况下,感觉就像是在调用一个由服务器实现的 GetAccount
函数。然而,这一切都是 gRPC 的工作,它会隐藏序列化和反序列化对象以及将这些数据发送到客户端和服务器的复杂过程。