3. gRPC 基础回顾:Protocol Buffers 语法、gRPC 四种通信模式及其适用场景

在开始报表导出架构重构之前,必须夯实 gRPC 的核心基础。本章将系统回顾 Protocol Buffers(protobuf) 的接口定义语法,以及 gRPC 的 四种通信模式。理解这些基础概念,是后续定义导出服务接口、规划消费组拓扑的前提。

3.1 Protocol Buffers 语法速览

gRPC 默认使用 Protocol Buffers 作为接口定义语言(IDL)和序列化协议。一个典型的 .proto 文件包含消息类型定义和服务定义。

3.1.1 消息类型定义

使用 message 关键字定义数据结构,每个字段有类型、名称和唯一的编号。

syntax = "proto3";

package reportexport;

// 定义导出请求消息
message ExportRequest {
  string report_id = 1;          // 报表唯一标识
  string format = 2;             // 导出格式:PDF, CSV, XLSX
  int32 page_size = 3;           // 分页大小(可选)
  bool include_charts = 4;       // 是否包含图表
  map<string, string> filters = 5; // 过滤条件
}

// 定义导出响应消息
message ExportResponse {
  string job_id = 1;             // 异步任务ID
  string status = 2;             // 任务状态:PENDING, RUNNING, COMPLETED, FAILED
  string download_url = 3;       // 下载链接(完成后提供)
}

3.1.2 服务定义

使用 service 关键字定义 RPC 方法,指定输入和输出消息类型。

service ReportExportService {
  // 一元 RPC:同步导出
  rpc ExportReport (ExportRequest) returns (ExportResponse);

  // 服务端流式 RPC:实时推送导出进度
  rpc ExportReportProgress (ExportRequest) returns (stream ProgressMessage);

  // 客户端流式 RPC:分批上传数据后导出
  rpc ExportFromStream (stream DataChunk) returns (ExportResponse);

  // 双向流式 RPC:实时交互式导出
  rpc InteractiveExport (stream ExportCommand) returns (stream ExportEvent);
}
字段编号规则: 1-15 编号使用 1 字节编码,适合频繁出现的字段;16-2047 编号使用 2 字节编码。预留 19000-19999 作为 protobuf 内部保留编号。

3.2 gRPC 四种通信模式

gRPC 基于 HTTP/2 提供了四种通信模式,分别适用于不同的业务场景。下表总结了它们的核心差异:

通信模式 请求方式 响应方式 典型场景
Unary(一元) 单次请求 单次响应 传统 RPC、查询、简单操作
Server Streaming(服务端流) 单次请求 多次响应(流) 进度推送、日志流、大文件分块
Client Streaming(客户端流) 多次请求(流) 单次响应 批量上传、数据采集、长事务提交
Bidirectional Streaming(双向流) 多次请求(流) 多次响应(流) 实时交互、聊天、协同编辑

3.3 四种模式详解与适用场景

3.3.1 Unary(一元 RPC)

客户端发送一个请求,服务端返回一个响应。这是最基础的 RPC 模式,行为与传统的 HTTP REST 类似。

  • 适用场景: 报表元数据查询、配置获取、简单的同步导出(小文件)。
  • 优点: 实现简单,调试方便,延迟可控。
  • 缺点: 不适合大数据量传输或长时间处理,客户端需等待完整响应。

3.3.2 Server Streaming(服务端流式 RPC)

客户端发送一个请求,服务端返回一个消息流。服务端可以持续推送数据,直到流结束。

  • 适用场景: 报表导出进度实时推送、大文件分块下载、实时日志流。
  • 优点: 客户端无需轮询,减少网络开销;支持实时反馈。
  • 缺点: 客户端需处理流式数据,连接可能因网络中断。

3.3.3 Client Streaming(客户端流式 RPC)

客户端发送一个消息流,服务端接收完所有消息后返回一个响应。

  • 适用场景: 批量上传报表数据、分段提交大型查询参数、IoT 设备数据采集。
  • 优点: 支持大数据量分片上传,降低单次请求负载。
  • 缺点: 服务端需等待所有数据到达后才能处理,延迟较高。

3.3.4 Bidirectional Streaming(双向流式 RPC)

客户端和服务端可以同时发送和接收消息流,两者独立且异步。

  • 适用场景: 实时交互式报表编辑、协同过滤、在线游戏状态同步。
  • 优点: 低延迟、全双工通信,适合需要频繁双向交互的场景。
  • 缺点: 实现复杂度高,需处理流状态管理和背压(backpressure)。
架构决策提示: 在报表导出架构中,服务端流式 RPC 是核心模式,用于实时推送导出进度和分块传输结果文件。双向流式 RPC 可用于高级交互式导出场景,但会增加消费组管理的复杂度,建议仅在明确需求时引入。

3.4 四种通信模式对比图

下图直观展示了四种模式的请求-响应交互流程:

gRPC 四种通信模式交互对比 Unary(一元) 客户端 → 服务端 请求 响应 1 请求 → 1 响应 Server Streaming 客户端 → 服务端 请求 1 请求 → N 响应 Client Streaming 客户端 → 服务端 N 请求 1 响应 Bidirectional 客户端 ↔ 服务端 请求 响应 N 请求 ↔ N 响应 架构选型建议 • 报表导出进度推送 → 服务端流式 RPC(Server Streaming) • 批量上传报表数据 → 客户端流式 RPC(Client Streaming) • 实时交互式报表编辑 → 双向流式 RPC(Bidirectional Streaming) • 简单查询或配置获取 → 一元 RPC(Unary) • 建议:优先使用服务端流式 RPC 作为导出任务的核心通信模式,降低消费组设计复杂度。

3.5 在报表导出架构中的映射

结合本课程的业务场景,四种模式在报表导出架构中的具体映射如下:

通信模式 报表导出场景 接口示例
Unary 查询导出任务状态、获取报表元数据 GetExportStatus(StatusRequest) returns (StatusResponse)
Server Streaming 实时推送导出进度、分块传输导出文件 ExportReportProgress(ExportRequest) returns (stream ProgressMessage)
Client Streaming 分批上传报表模板或数据源 UploadTemplate(stream TemplateChunk) returns (UploadResponse)
Bidirectional Streaming 交互式报表参数调整与预览 InteractiveExport(stream ExportCommand) returns (stream ExportEvent)
关键结论: 在后续的消费组规划中,服务端流式 RPC 将作为导出任务的核心通信模式,用于实现进度推送和结果分块传输。一元 RPC 用于管理面操作(查询状态、取消任务)。客户端流式 和 双向流式 作为高级特性,仅在特定需求下引入。