关于 gRPC 服务和客户端应用程序,目前已经介绍了在给定的 gRPC 服务器端上注册唯一的 gRPC 服务,并且由单个客户端存根使用 gRPC 客户端进行连接。但是,gRPC 还允许在同一个 gRPC 服务器端上运行多个 gRPC 服务(见图 5-4),也允许多个客户端存根使用同一个 gRPC客户端连接,这种功能叫作多路复用(multiplexing)。
例如,在 OrderManagement
服务示例中,假设为了满足订单管理需求,希望在同一个 gRPC 服务器端运行另一个服务,这样客户端就能重用同一个连接,从而按需调用这两个服务。通过对应的服务器端注册函数,也就是 ordermgt_pb.RegisterOrderManagementServer
和hello_pb.RegisterGreeterServer
,可以在同一个服务器端注册这两个服务,如代码清单 5-9 所示。
代码清单 5-9 两个 gRPC 服务共享同一个服务器端(grpc.Server)
func main() {
initSampleData()
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer() ➊
// 在gRPC orderMgtServer上注册订单管理服务
ordermgt_pb.RegisterOrderManagementServer(grpcServer, &orderMgtServer{}) ➋
// 在gRPC orderMgtServer上注册问候服务
hello_pb.RegisterGreeterServer(grpcServer, &helloServer{}) ➌
...
}
- ❶ 创建 gRPC 服务器端。
- ❷ 在 gRPC 服务器端注册 OrderManagement 服务。
- ❸ 在同一个 gRPC 服务器端注册 Hello 服务。
同理,通过客户端,可以在两个 gRPC 客户端存根间共享相同的 gRPC连接。
如代码清单 5-10 所示,因为两个 gRPC 服务在同一个 gRPC 服务器端运行,所以可以创建一个 gRPC 连接,并在为两个服务创建 gRPC 客户端实例时使用该连接。
代码清单 5-10 两个 gRPC 客户端存根共享同一个连接(grpc.ClientConn)
// 建立到服务器端的连接
conn, err := grpc.Dial(address, grpc.WithInsecure()) ➊
...
orderManagementClient := pb.NewOrderManagementClient(conn) ➋
...
// 添加订单的RPC
...
res, addErr := orderManagementClient.AddOrder(ctx, &order1)
...
helloClient := hwpb.NewGreeterClient(conn) ➌
...
// 打招呼的RPC
helloResponse, err := helloClient.SayHello(hwcCtx,&hwpb.HelloRequest{Name: "gRPC Up and Running!"})
...
- ❶ 创建 gRPC 连接。
- ❷ 使用创建的 gRPC 连接来建立 OrderManagement 客户端。
- ❸ 使用相同的 gRPC 连接来建立 Hello 客户端。
对于多个服务或者多个存根使用相同的连接,这只涉及设计形式,与gRPC 理念无关。在微服务等大多数日常使用场景中,通常并不会在两个服务间共享同一个 gRPC 服务器端。
在微服务架构中,gRPC 多路复用的一个强大的用途就是在同一个服务器端进程中托管同一个服务的多个主版本。这样做能够保证 API 在发生破坏性变更之后,依然能够适应遗留的客户端。一旦服务契约的旧版本不再有效,就可以在服务器端将其移除了。
5.6 节将讨论在客户端和服务器端通信的过程中,如何交换非 RPC 参数和非 RPC 响应的数据。