1. gRPC 基础回顾

在深入事务边界与错误处理之前,必须重新校准 gRPC 的核心知识体系。本章从 核心概念、Protocol Buffers 定义 和 四种通信模式 三个维度展开,为后续中间件落地建立统一的术语与结构基础。

1.1 gRPC 核心概念

gRPC 是一个高性能、开源、通用的 RPC 框架,基于 HTTP/2 协议传输,使用 Protocol Buffers 作为接口定义语言(IDL)。其核心组件包括:

概念 说明 中间件关注点
Service 定义远程方法的逻辑集合 拦截器作用范围、事务边界划分
RPC Method Service 中的具体远程调用方法 错误码映射、超时控制粒度
Stub 客户端代理,屏蔽网络细节 重试策略、负载均衡入口
Channel 与单个 gRPC 服务器的连接抽象 连接池管理、TLS 终止
Interceptor 请求/响应链中的拦截钩子 事务传播、错误包装的核心扩展点
Metadata 键值对形式的附加信息(类似 HTTP Header) 事务 ID 传递、分布式上下文传播
中间件视角: Channel 和 Interceptor 是中间件植入事务边界与错误处理逻辑的两个关键锚点。Channel 负责连接生命周期,Interceptor 负责请求级别的横切逻辑。

1.2 Protocol Buffers 定义

Protocol Buffers(proto3)是 gRPC 的接口定义语言,同时承担数据序列化格式的角色。一个典型的服务定义包含 message 和 service 两个核心元素。

syntax = "proto3";

package ecommerce.order;

// 订单服务 —— 事务边界示例
service OrderService {
  rpc CreateOrder (CreateOrderRequest) returns (CreateOrderResponse);
  rpc GetOrderStatus (GetOrderStatusRequest) returns (stream OrderStatusUpdate);
  rpc UploadInvoice (stream InvoiceChunk) returns (UploadInvoiceResponse);
  rpc ProcessPayment (stream PaymentEvent) returns (stream PaymentResult);
}

message CreateOrderRequest {
  string user_id = 1;
  repeated string product_ids = 2;
  double total_amount = 3;
  map<string, string> metadata = 4;  // 用于传递事务上下文
}

message CreateOrderResponse {
  string order_id = 1;
  int32 status_code = 2;
  string error_message = 3;
}

message OrderStatusUpdate {
  string order_id = 1;
  string status = 2;
  int64 timestamp = 3;
}

message InvoiceChunk {
  bytes chunk_data = 1;
  int32 chunk_index = 2;
  bool is_last = 3;
}

message PaymentEvent {
  string transaction_id = 1;
  double amount = 2;
  string currency = 3;
}

message PaymentResult {
  bool success = 1;
  string receipt_url = 2;
  string error_detail = 3;
}

message UploadInvoiceResponse {
  bool accepted = 1;
  string invoice_url = 2;
}
关键设计原则:
  • 每个 RPC 方法应显式定义独立的 Request/Response 消息,避免复用通用包装器。
  • 在 message 中预留 map<string, string> metadata 字段,用于中间件注入事务 ID、trace ID 等上下文。
  • 错误信息应包含在 response 消息中(如 status_code + error_message),而非仅依赖 gRPC 状态码。

1.3 四种通信模式

gRPC 基于 HTTP/2 的流式能力,定义了四种 RPC 模式。理解每种模式下的数据流特征,是设计事务边界和错误处理策略的前提。

gRPC 四种通信模式对比 Unary RPC 客户端 → 服务器 单个请求 + 单个响应 适用:查询、创建 事务:简单提交/回滚 错误:立即返回状态码 ★ 最易实现事务边界 Server Streaming 客户端 → 服务器 单个请求 + 流式响应 适用:订阅、日志推送 事务:流中无法回滚 错误:流中断 + 状态码 ★ 需提前校验事务状态 Client Streaming 客户端 → 服务器 流式请求 + 单个响应 适用:上传、批量提交 事务:流结束后提交 错误:流结束后返回 ★ 需缓冲或两阶段提交 Bidirectional 客户端 ↔ 服务器 流式请求 + 流式响应 适用:实时游戏、聊天 事务:全双工协调 错误:流级 + 消息级 ★ 事务边界最复杂 中间件设计启示 流式模式(Server/Client/Bidirectional)的事务边界不能依赖单次请求-响应周期, 必须引入流生命周期管理、消息序号追踪和分布式事务协调器。

1.4 四种模式的事务边界特征

模式 请求/响应特征 事务边界 错误处理时机 中间件拦截点
Unary 1 请求 → 1 响应 单次调用内 响应到达时 客户端/服务端拦截器
Server Streaming 1 请求 → N 响应 从请求到流关闭 流中断或结束时 服务端拦截器 + 流事件
Client Streaming N 请求 → 1 响应 从首消息到流关闭 流关闭后 客户端拦截器 + 流事件
Bidirectional N 请求 ↔ N 响应 全双工生命周期 任意时刻 双向拦截器 + 消息序号
常见误区: 很多开发者将 Unary 模式的事务处理逻辑直接套用到流式模式,导致在 Server Streaming 中尝试“回滚已发送的流消息”,或在 Bidirectional 中丢失消息级错误。流式模式必须重新设计事务边界,不能复用 Unary 的简单提交/回滚模型。

1.5 四种模式的代码骨架

以下代码片段展示四种模式在服务端的基本实现骨架,重点标注事务边界和错误处理的占位位置。

// Unary RPC —— 事务边界最清晰
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse) {
  // 事务开始:拦截器可在此注入事务ID
  // 业务逻辑:创建订单
  // 事务结束:提交或回滚
  // 错误处理:返回 gRPC 状态码 + 业务错误码
}

// Server Streaming —— 事务在流开启前决定
rpc GetOrderStatus(GetOrderStatusRequest) returns (stream OrderStatusUpdate) {
  // 事务开始:校验请求参数,决定是否开启流
  // 流中发送多条 OrderStatusUpdate
  // 事务结束:流关闭时提交
  // 错误处理:流中断时发送错误状态码
}

// Client Streaming —— 事务在流结束后提交
rpc UploadInvoice(stream InvoiceChunk) returns (UploadInvoiceResponse) {
  // 事务开始:接收第一个 chunk 时创建临时缓冲区
  // 流中接收多个 InvoiceChunk
  // 事务结束:收到 is_last=true 后组装并提交
  // 错误处理:流关闭后返回 UploadInvoiceResponse 中的错误字段
}

// Bidirectional Streaming —— 事务需消息级协调
rpc ProcessPayment(stream PaymentEvent) returns (stream PaymentResult) {
  // 事务开始:双方协商事务ID
  // 流中:每个 PaymentEvent 对应一个 PaymentResult
  // 事务结束:任意一方发送结束标记
  // 错误处理:消息级错误 + 流级错误双重机制
}
中间件落地要点:
  • Unary 模式:拦截器可以安全地在请求前后包裹事务生命周期。
  • 流式模式:拦截器需要监听 onOpen、onMessage、onClose 事件,不能仅依赖方法前后置。
  • 所有模式:Metadata 是传递事务上下文的唯一可靠通道,不要在消息体中硬编码事务 ID。

1.6 本章小结

gRPC 基础回顾为后续章节建立了三个关键认知:

  • Protocol Buffers 是服务契约的基石,message 设计直接影响事务上下文的传递能力。
  • 四种通信模式 决定了事务边界的形状——Unary 是点,流式模式是线或面。
  • Interceptor + Metadata 是中间件实现事务传播和错误包装的标准扩展点,后续章节将在此基础上构建分布式事务协调器。