一文了解gRPC 核心原理

59 阅读7分钟

gRPC 核心原理详解

gRPC 是由 Google 开源的高性能、跨语言的远程过程调用(RPC)框架,基于 HTTP/2 协议设计,使用 Protocol Buffers(Protobuf)作为接口定义语言(IDL)和序列化格式。其核心目标是让不同服务之间的通信像调用本地函数一样简单,同时兼顾高性能、低延迟和跨平台特性。

一、gRPC 核心架构与通信模型

gRPC 遵循经典的 RPC 通信模型,核心分为客户端(Client)  和服务端(Server) ,并通过「存根(Stub)」屏蔽底层通信细节,整体架构如下:

1. 核心组件

组件作用
服务定义(IDL)基于 Protobuf 定义服务接口(方法名、参数、返回值),生成多语言代码
客户端存根(Stub)客户端侧的代理对象,封装网络通信逻辑,让用户以本地函数方式调用远程方法
服务端存根(Skeleton)服务端侧的代理对象,接收客户端请求,解析后转发给实际业务逻辑实现
序列化 / 反序列化基于 Protobuf 将请求 / 响应数据编码为二进制(高效压缩、跨语言)
传输层基于 HTTP/2 实现双向流、多路复用、头部压缩等特性
协议层gRPC 封装的请求 / 响应协议(如请求头、消息体、状态码)

2. 核心通信流程

  1. 定义服务:通过 Protobuf IDL 定义服务接口(如 service UserService { rpc GetUser(GetUserReq) returns (GetUserResp); });
  2. 生成代码:使用 gRPC 插件根据 IDL 生成客户端 Stub 和服务端 Skeleton 代码(支持 Go、Java、Python 等多语言);
  3. 客户端调用:用户调用 Stub 上的本地方法,Stub 将参数序列化为 Protobuf 二进制,封装为 HTTP/2 请求;
  4. 服务端处理:服务端接收 HTTP/2 请求,反序列化参数,调用实际业务实现,将返回值序列化后通过 HTTP/2 响应返回;
  5. 客户端接收:Stub 反序列化响应数据,返回给用户,完成一次 RPC 调用。

二、核心技术原理

1. 基于 HTTP/2 的传输层

gRPC 选择 HTTP/2 作为底层传输协议,而非 TCP 直接封装,核心优势源于 HTTP/2 的特性:

(1)二进制帧(Binary Framing)

HTTP/1.x 基于文本格式,解析效率低;HTTP/2 将所有数据拆分为二进制帧(Frame),包括请求行、头部、消息体,解析速度大幅提升,适配 Protobuf 的二进制序列化特性。

(2)多路复用(Multiplexing)
  • HTTP/1.x 一个 TCP 连接只能处理一个请求(串行),并发需建立多个连接;
  • HTTP/2 允许在单个 TCP 连接上同时处理多个请求 / 响应(多路复用),每个请求对应一个「流(Stream)」,流之间互不阻塞,大幅减少连接开销,提升并发性能。
(3)双向流(Bidirectional Streaming)

HTTP/2 支持全双工通信:客户端和服务端可在同一连接上同时发送数据流,为 gRPC 的「流式 RPC」提供基础(如客户端流、服务端流、双向流)。

(4)头部压缩(HPACK)

HTTP/2 使用 HPACK 算法压缩请求 / 响应头部,减少重复头部(如 content-typegrpc-status)的传输体积,降低网络开销。

(5)服务端推送(Server Push)

HTTP/2 支持服务端主动向客户端推送数据,gRPC 可基于此实现服务端主动通知场景(如实时消息)。

2. Protobuf 序列化原理

gRPC 以 Protobuf 作为默认 IDL 和序列化格式,核心优势是「高效、紧凑、跨语言」:

(1)数据编码方式

Protobuf 采用「键值对 + 变长编码(Varint)」的二进制格式,相比 JSON/XML:

  • 体积更小:例如一个整数 100,JSON 需 3 个字符,Protobuf 仅需 1 个字节;
  • 解析更快:无需字符串解析,直接按预定义结构解码。
(2)接口定义与代码生成

通过 Protobuf 的 service 和 rpc 关键字定义服务接口,例如:

protobuf

syntax = "proto3";
package user;

// 请求结构
message GetUserReq {
  int64 user_id = 1;
}

// 响应结构
message GetUserResp {
  string name = 1;
  int32 age = 2;
}

// 服务定义
service UserService {
  // 简单 RPC
  rpc GetUser(GetUserReq) returns (GetUserResp);
  // 服务端流 RPC
  rpc ListUsers(ListUsersReq) returns (stream GetUserResp);
  // 客户端流 RPC
  rpc BatchAddUser(stream AddUserReq) returns (BatchAddUserResp);
  // 双向流 RPC
  rpc Chat(stream ChatMsg) returns (stream ChatMsg);
}

通过 protoc 工具 + gRPC 插件,可生成多语言的:

  • 客户端 Stub:包含调用远程方法的封装函数;
  • 服务端 Skeleton:包含服务注册、请求解析的框架代码,用户只需实现业务逻辑。

3. 四种 RPC 调用模式

gRPC 基于 HTTP/2 流特性,支持四种调用模式,覆盖不同业务场景:

模式特点适用场景
简单 RPC(Unary)客户端发单个请求,服务端返回单个响应普通查询(如获取用户信息)
服务端流 RPC客户端发单个请求,服务端返回流式响应(多次发送)大数据分页返回(如列表查询)
客户端流 RPC客户端流式发送请求,服务端返回单个响应批量上传(如日志上报)
双向流 RPC客户端和服务端双向流式通信,双方可独立发送 / 接收数据实时交互(如聊天、直播)

4. 拦截器(Interceptor)与生命周期

gRPC 支持客户端和服务端的拦截器,可在 RPC 调用的生命周期中插入自定义逻辑:

  • 客户端拦截器:调用 Stub 方法前 / 后执行(如添加请求头、日志、超时控制);
  • 服务端拦截器:接收请求前 / 返回响应后执行(如认证、授权、监控、限流)。

核心生命周期(以简单 RPC 为例):

plaintext

客户端                服务端
  │                     │
  │ 1. 调用 Stub 方法    │
  │ 2. 序列化请求        │
  │ 3. 发送 HTTP/2 请求  │
  │────────────────────>│
  │                     │ 4. 反序列化请求
  │                     │ 5. 执行服务端拦截器
  │                     │ 6. 调用业务实现
  │                     │ 7. 序列化响应
  │                     │ 8. 发送 HTTP/2 响应
  │<────────────────────│
  │ 9. 反序列化响应      │
  │ 10. 返回结果给用户   │
  │                     │

5. 负载均衡与服务发现

gRPC 内置负载均衡(LB)框架,支持两种模式:

  • 客户端负载均衡:客户端维护服务端地址列表,通过轮询 / 哈希等策略选择目标节点(需结合服务发现组件如 Consul、ETCD);
  • 代理负载均衡:通过 gRPC Gateway 或第三方代理(如 Nginx、Envoy)转发请求,服务端地址由代理维护。

核心原理:客户端通过「名称解析器(Name Resolver)」获取服务端地址列表,通过「负载均衡策略(LB Policy)」选择节点,建立 HTTP/2 连接并发送请求。

6. 错误处理与状态码

gRPC 定义了标准化的状态码(gRPC Status Code),替代 HTTP 状态码,更贴合 RPC 场景:

状态码含义示例
OK (0)成功调用正常完成
CANCELLED (1)调用被取消客户端主动取消请求
NOT_FOUND (5)资源未找到查询的用户 ID 不存在
UNAVAILABLE (14)服务不可用服务端宕机或网络中断

错误信息通过 grpc-status 和 grpc-message 头部传递,支持自定义错误详情(通过 Protobuf 扩展)。

三、gRPC 核心优势与适用场景

1. 核心优势

  • 高性能:HTTP/2 + Protobuf 组合,相比 REST API(HTTP/1.1 + JSON),延迟降低 30%+,带宽占用减少 60%+;
  • 跨语言:支持 10+ 主流语言(Go、Java、Python、C++ 等),适合微服务多语言栈;
  • 强类型:Protobuf 定义接口,编译期校验参数类型,避免运行时类型错误;
  • 流式通信:原生支持双向流,适配实时交互场景;
  • 轻量级:二进制协议 + 头部压缩,适配移动端 / 物联网等带宽受限场景。

2. 适用场景

  • 微服务内部通信(替代 REST API,提升性能);
  • 跨语言服务调用(如 Go 服务调用 Java 服务);
  • 实时数据流场景(如直播、聊天、日志上报);
  • 移动端 / 物联网设备通信(带宽 / 性能受限)。

3. 不适用场景

  • 对外公开的 API(需兼容浏览器,gRPC 不直接支持浏览器,需通过 gRPC-Web 中转);
  • 简单的 CRUD 场景(REST API 更易调试和兼容)。

四、总结

gRPC 的核心原理可概括为:以 Protobuf 为接口定义和序列化基础,基于 HTTP/2 实现高效的跨语言远程过程调用,通过 Stub 屏蔽底层通信细节,支持多种调用模式和扩展能力。其本质是将「远程函数调用」封装为「HTTP/2 二进制请求 / 响应」,兼顾性能、易用性和跨平台特性,成为微服务通信的主流选择。