我们从最简单的 RPC 风格开始讨论 gRPC 通信模式。一元 RPC 模式也被称为简单 RPC 模式。在该模式中,当客户端调用服务器端的远程方法时,客户端发送请求至服务器端并获得一个响应,与响应一起发送的还有状态细节以及 trailer 元数据。事实上,这也是第 1 章和第 2 章所介绍的通信模式。接下来看一个真实的用例,来进一步了解一元 RPC 模式。

假设需要为基于 gRPC 的在线零售应用程序构建 OrderManagement 服务,并在该服务中实现 getOrder 方法。借助该方法,客户端可以通过订单 ID 检索已有的订单。如图 3-1 所示,客户端发送一个带有订单 ID的请求,服务器端给出响应,响应中包含订单的信息。因此,它遵循一元 RPC 模式。

图 3-1:一元 RPC 模式

下面来实现这种模式。第一步就是为 OrderManagement 服务及其getOrder 方法创建服务定义。如代码清单 3-1 所示,可以使用 protocolbuffers 进行服务定义,getOrder 远程方法接受一个订单 ID 的请求,并且会给出一个包含 Order 消息的响应。在本用例中,Order 消息具有描述订单所需的结构。

代码清单 3-1 OrderManagement 服务定义,服务中的 getOrder方法遵循一元 RPC 模式

syntax = "proto3";
import "google/protobuf/wrappers.proto"; ➊
package ecommerce;
service OrderManagement {
    rpc getOrder(google.protobuf.StringValue) returns (Order); ➋
}
message Order { ➌
    string id = 1;
    repeated string items = 2; ➍
    string description = 3;
    float price = 4;
    string destination = 5;
}

❶ 导入这个包,从而使用常见的类型,如 StringValue。
❷ 检索订单的远程方法。
❸ 定义 Order 类型。
❹ 使用 repeated 表明这个字段在消息中可以重复出现任意次,包括 0次。在这里,一条订单消息可以有任意数量的条目。

然后,借助 gRPC 服务定义的 proto 文件,就可以生成服务器端骨架代码并实现 GetOrder 方法的逻辑了。代码清单 3-2 展示了OrderManagement 服务的 Go 实现。作为 GetOrder 方法的输入,单个订单 ID(String)用来组成请求,这样做可以很容易地在服务器端找到订单并以 Order 消息(Order 结构体)的形式进行响应。Order 消息可以和 nil 错误一起返回,从而告诉 gRPC,我们已经处理完 RPC,可以将 Order 返回到客户端了。

代码清单 3-2 使用 Go 语言编写的 OrderManagement 服务的GetOrder 方法实现

// server/main.go
func (s *server) GetOrder(ctx context.Context, orderId *wrapper.StringValue) (*pb.Order, error) {
    // 服务实现.
    ord := orderMap[orderId.Value]
    return &ord, nil
}

第 4 章将介绍关于 gRPC 服务器端和客户端完整消息流的更多细节。除了在服务定义中为 GetOrder 方法所指定的参数,可以看到,在 OrderManagement 服务的 Go 实现中,还有一个Context 参数被传递到了方法中。Context 包含一些用于控制gRPC 行为的构造,比如截止时间和取消功能。第 5 章会详细讨论这些概念。

现在来实现客户端的逻辑,从而远程调用 GetOrder 方法。与服务器端的实现一样,可以为自己喜欢的语言生成代码来创建客户端存根,然后使用该存根调用服务,代码清单 3-3 使用 Go gRPC 客户端调用OrderManagement 服务。当然,首先要创建到服务器端的连接并初始化调用服务的客户端存根。然后,就可以调用客户端存根的 GetOrder方法,从而实现对远程方法的调用。这时会得到一个 Order 消息作为响应,其中包含服务定义中使用 protocol buffers 所定义的订单信息。

代码清单 3-3 使用 Go 语言调用远程 GetOrder 方法的客户端实现

// 建立到服务器端的连接.
...
orderMgtClient := pb.NewOrderManagementClient(conn)
...
// 获取订单
retrievedOrder , err := orderMgtClient.GetOrder(ctx,&wrapper.StringValue{Value: "106"})
log.Print("GetOrder Response -> : ", retrievedOrder)

这种一元 RPC 模式非常容易实现,适用于大多数进程间通信用例。在多种语言间,实现方式都是非常类似的,本书的示例代码仓库提供了Go 和 Java 的源代码。

现在,我们已经对一元 RPC 模式有了大致的了解,接下来看一下服务器端流 RPC 模式。

文档更新时间: 2023-09-02 04:30   作者:Minho