2. gRPC 基础回顾:通信模型、Protocol Buffers 与 RPC 类型

在深入拦截器与 GC 停顿排查之前,必须牢固掌握 gRPC 的核心通信模型与数据序列化机制。本章将系统回顾 gRPC 的通信架构、Protocol Buffers 的编码原理,以及一元与流式 RPC 的交互模式,为后续的拦截器超时分析与性能调优奠定基础。

2.1 gRPC 通信模型

gRPC 基于 HTTP/2 协议构建,采用 客户端-服务端 架构,通过 Protocol Buffers 作为接口定义语言(IDL)与数据序列化格式。其核心通信模型包含以下层次:

  • 传输层:HTTP/2 提供多路复用、流控、头部压缩等特性,允许在单一 TCP 连接上并发处理多个 RPC 调用。
  • 协议层:gRPC 定义了一套标准的请求-响应消息格式,包括请求头、消息体、状态码与尾部元数据。
  • 业务层:开发者通过 .proto 文件定义服务接口与消息结构,gRPC 自动生成客户端与服务端代码。
关键特性: gRPC 默认使用 Protocol Buffers 进行序列化,相比 JSON 体积更小、解析速度更快,尤其适合高吞吐、低延迟的微服务场景。
gRPC 通信模型分层架构 业务层(Service Layer) .proto 定义服务接口 · 自动生成 Stub · 拦截器链 协议层(Protocol Layer) gRPC 消息格式 · 状态码 · 元数据 · 流控 传输层(Transport Layer) HTTP/2 · 多路复用 · 头部压缩 · 单一 TCP 连接

2.2 Protocol Buffers 核心概念

Protocol Buffers(protobuf)是 gRPC 的默认序列化框架,通过 .proto 文件定义数据结构与服务接口。其核心要素包括:

概念 说明 示例
消息(Message) 定义结构化数据,包含多个字段 message UserRequest { string id = 1; }
字段编号 每个字段有唯一编号,用于二进制编码 int32 age = 2; 中的 2
字段类型 支持标量、枚举、嵌套消息、repeated 等 repeated string tags = 3;
服务(Service) 定义 RPC 方法签名 rpc GetUser(UserRequest) returns (UserResponse);
性能提示: 字段编号 1~15 使用 1 字节编码,16~2047 使用 2 字节编码。高频字段应分配小编号以减小消息体积。

2.3 一元 RPC 与流式 RPC

gRPC 支持四种 RPC 类型,其中 一元 RPC 和 流式 RPC 是最常用的两种模式。理解它们的交互流程对拦截器超时设置与 GC 停顿分析至关重要。

2.3.1 一元 RPC(Unary RPC)

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

// proto 定义
service UserService {
  rpc GetUser (UserRequest) returns (UserResponse);
}

// 客户端调用(Go 示例)
resp, err := client.GetUser(ctx, &pb.UserRequest{Id: "123"})
if err != nil {
    log.Fatalf("RPC 失败: %v", err)
}
log.Printf("用户名称: %s", resp.Name)

2.3.2 流式 RPC(Streaming RPC)

流式 RPC 允许在单一调用中传输多条消息,分为三种子类型:

  • 服务端流式:客户端发送一个请求,服务端返回消息流。
  • 客户端流式:客户端发送消息流,服务端返回一个响应。
  • 双向流式:双方独立发送消息流,顺序由应用层保证。
// 服务端流式示例
rpc ListUsers (UserListRequest) returns (stream UserResponse);

// 客户端接收流
stream, _ := client.ListUsers(ctx, &pb.UserListRequest{Page: 1})
for {
    user, err := stream.Recv()
    if err == io.EOF {
        break
    }
    log.Printf("收到用户: %s", user.Name)
}
一元 RPC 与流式 RPC 交互对比 一元 RPC 客户端 服务端 请求 响应 1 请求 → 1 响应 类似 HTTP 请求-响应 拦截器在调用前后执行 流式 RPC(以服务端流为例) 客户端 服务端 请求 消息 1 消息 2 消息 N 1 请求 → N 响应 拦截器在流生命周期内多次触发

2.4 拦截器在通信模型中的位置

gRPC 拦截器(Interceptor)位于业务层与协议层之间,可以拦截每个 RPC 调用的请求与响应。拦截器分为两类:

拦截器类型 作用范围 典型用途
一元拦截器 一元 RPC 调用 超时控制、日志记录、认证、指标采集
流式拦截器 流式 RPC 调用 流控、消息计数、错误重试、上下文传递
注意: 流式拦截器在流的整个生命周期内可能被多次调用,超时与 GC 停顿的影响比一元拦截器更复杂。后续章节将重点分析流式场景下的性能问题。

2.5 本章小结

gRPC 基于 HTTP/2 与 Protocol Buffers 构建,提供高效、跨语言的 RPC 通信能力。一元 RPC 适用于简单的请求-响应模式,流式 RPC 则适合大数据量推送或实时通信场景。拦截器作为 gRPC 的可插拔中间件,在超时控制、日志、认证等方面发挥关键作用,也是后续排查 GC 停顿与超时问题的核心切入点。