4. gRPC 服务定义:Service 定义语法与 RPC 方法类型

在 gRPC 的契约设计中,Service 定义是核心入口。它使用 Protocol Buffers(Protobuf)的 IDL(接口定义语言)来声明远程方法的签名、参数和返回类型。本章将深入解析 service 关键字的语法结构,并逐一拆解四种 RPC 方法类型的适用场景与通信模型。

4.1 Service 定义语法

一个完整的 gRPC 服务定义由 service 关键字引导,内部包含一个或多个 rpc 方法声明。每个方法必须指定请求消息类型和响应消息类型。

核心语法模板:
service 服务名称 {
    // 一元 RPC
    rpc 方法名(请求消息类型) returns (响应消息类型);

    // 服务器流式 RPC
    rpc 方法名(请求消息类型) returns (stream 响应消息类型);

    // 客户端流式 RPC
    rpc 方法名(stream 请求消息类型) returns (响应消息类型);

    // 双向流式 RPC
    rpc 方法名(stream 请求消息类型) returns (stream 响应消息类型);
}
命名规范:服务名称使用 PascalCase(如 UserService),方法名使用 PascalCase(如 GetUser),消息类型同样使用 PascalCase。文件扩展名为 .proto。

4.2 四种 RPC 方法类型

gRPC 基于 HTTP/2 的流式能力,定义了四种通信模式。下表从数据流向、典型场景和实现复杂度三个维度进行对比:

方法类型 请求模式 响应模式 典型场景 实现复杂度
Unary(一元) 单条消息 单条消息 查询用户信息、创建订单 低
Server Streaming(服务端流) 单条消息 多条消息(流) 实时推送、日志订阅、大文件下载 中
Client Streaming(客户端流) 多条消息(流) 单条消息 批量上传、传感器数据聚合 中
Bidirectional Streaming(双向流) 多条消息(流) 多条消息(流) 实时聊天、游戏同步、AI 对话 高

4.3 四种方法类型详解

4.3.1 Unary RPC(一元 RPC)

最基础的 RPC 模式,客户端发送一个请求,服务端返回一个响应。语义上等同于传统的 HTTP 请求-响应模型,但底层使用 HTTP/2 和 Protobuf 序列化,性能更高。

service OrderService {
    rpc GetOrder(GetOrderRequest) returns (Order);
}

message GetOrderRequest {
    string order_id = 1;
}

message Order {
    string id = 1;
    string product_name = 2;
    double price = 3;
}

4.3.2 Server Streaming RPC(服务端流式 RPC)

客户端发送一个请求,服务端通过流式响应返回多条消息。适用于服务端需要持续推送数据的场景,例如实时监控指标、日志流或大文件分块传输。

service LogService {
    rpc SubscribeLogs(LogFilter) returns (stream LogEntry);
}

message LogFilter {
    string level = 1;  // "info", "error", "debug"
}

message LogEntry {
    string timestamp = 1;
    string message = 2;
}

4.3.3 Client Streaming RPC(客户端流式 RPC)

客户端通过流式请求发送多条消息,服务端在所有消息接收完毕后返回一个统一的响应。常用于批量数据提交、文件上传或需要聚合计算的场景。

service UploadService {
    rpc UploadChunks(stream Chunk) returns (UploadStatus);
}

message Chunk {
    bytes data = 1;
    int32 sequence = 2;
}

message UploadStatus {
    bool success = 1;
    string message = 2;
}

4.3.4 Bidirectional Streaming RPC(双向流式 RPC)

客户端和服务端可以独立地、并发地发送和接收消息流。双方可以按任意顺序读写,实现全双工通信。这是 gRPC 最强大的模式,适合实时交互场景。

service ChatService {
    rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}

message ChatMessage {
    string user_id = 1;
    string content = 2;
    int64 timestamp = 3;
}
注意:双向流并不要求客户端和服务端的消息一一对应。服务端可以在收到客户端第一条消息后立即开始回复,也可以等待客户端发送完所有消息后再统一回复。具体行为由业务逻辑决定。

4.4 四种 RPC 方法类型对比图

下图直观展示了四种 RPC 方法类型的通信模式差异:

四种 gRPC 方法类型通信模式对比 Unary RPC Client Server 请求 响应 Server Streaming Client Server 请求 流响应 Client Streaming Client Server 流请求 响应 Bidirectional Client Server 双向流 图例说明 客户端节点 服务端节点 消息流向 • Unary:最常用,适合请求-响应模式,如 REST API 迁移。 • Server Streaming:服务端主动推送,适合实时数据订阅。 • Client Streaming:客户端批量提交,适合数据聚合上传。 • Bidirectional Streaming:全双工通信,适合实时交互系统。 • 选择依据:根据数据流向是“单次”还是“流式”决定。

4.5 选择 RPC 方法类型的决策流程

在实际项目中,选择哪种 RPC 方法类型取决于业务需求。以下决策流程可以帮助你快速判断:

  1. 客户端是否需要发送多条消息?
    • 否 → 进入第 2 步
    • 是 → 进入第 3 步
  2. 服务端是否需要返回多条消息?
    • 否 → Unary RPC
    • 是 → Server Streaming RPC
  3. 服务端是否需要返回多条消息?
    • 否 → Client Streaming RPC
    • 是 → Bidirectional Streaming RPC
最佳实践:优先从 Unary RPC 开始设计,只有在明确需要流式通信时才升级到流式模式。过度设计流式接口会增加客户端和服务端的复杂度。

4.6 本章小结

Service 定义是 gRPC 契约的骨架,service 关键字和 rpc 方法声明构成了接口的完整签名。四种 RPC 方法类型——Unary、Server Streaming、Client Streaming、Bidirectional Streaming——分别对应不同的数据流模式。理解它们的语法和语义,是后续进行服务拆分、接口版本管理和性能优化的基础。