什么是 RPC
RPC(Remote Procedure Call,远程过程调用)是一种通信协议,让程序可以像调用本地函数一样调用远程机器上的函数,而无需关心底层网络传输细节。
当你调用 userService.GetUser(ctx, &GetUserRequest{Id: 123}) 时,这行代码在网络上传输,由另一台服务器上的 Go 程序执行,返回结果给你——这就是 RPC 的魔法。
RPC vs REST:设计哲学的根本差异
# 资源导向(名词 + 动词)
GET /users/123
POST /users
PUT /users/123
DELETE /users/123
# 数据格式:JSON(文本)
{
"id": 123,
"name": "Alice",
"email": "alice@example.com"
}
// 过程导向(动词)
rpc GetUser(GetUserRequest)
returns (UserResponse)
rpc CreateUser(CreateUserRequest)
returns (UserResponse)
// 数据格式:Protobuf(二进制)
// 比 JSON 体积小 3-10 倍
| 对比维度 | REST | gRPC |
|---|---|---|
| 协议 | HTTP/1.1(通常) | HTTP/2(必须) |
| 序列化 | JSON(文本) | Protobuf(二进制) |
| 接口定义 | OpenAPI/Swagger(可选) | .proto 文件(必须) |
| 类型安全 | 弱(运行时校验) | 强(编译时校验) |
| 流式传输 | SSE/WebSocket(额外) | 原生四种流式模式 |
| 代码生成 | 可选 | 内置,多语言 |
| 浏览器支持 | 直接支持 | 需要代理(grpc-web) |
| 可读性 | 高(JSON 人类可读) | 低(二进制需工具) |
| 适用场景 | 公开 API、BFF、移动端 | 微服务内部通信 |
HTTP/2 基础:gRPC 的传输基础
gRPC 强制要求 HTTP/2,这是它高性能的根本原因。理解 HTTP/2 的三大核心特性,就理解了 gRPC 为什么快。
多路复用(Multiplexing)
HTTP/1.1 的一个连接同一时刻只能处理一个请求(即使使用 Keep-Alive 也只能串行)。HTTP/2 将所有数据拆分为 帧(Frame),每个请求/响应是一个 流(Stream),多个流可以在同一个 TCP 连接上并发传输——彻底解决了队头阻塞(Head-of-Line Blocking)问题。
HTTP/1.1(6 个请求需要多个连接):
连接1: [请求A] ─── [响应A]
连接2: [请求B] ─── [响应B]
连接3: [请求C] ─── [响应C]
HTTP/2(6 个请求复用 1 个连接):
连接1: [帧A1][帧B1][帧C1][帧A2][帧C2][帧B2]...
↑交错发送,互不阻塞
头部压缩(HPACK)
HTTP/1.1 每次请求都要发送完整的 HTTP 头(如 Cookie、User-Agent 等),往往比实际数据还大。HTTP/2 使用 HPACK 算法压缩头部,对于重复的头字段只发送差量,节省大量带宽。
服务端推送(Server Push)
服务端可以在客户端请求之前主动推送资源(gRPC 的流式模式即基于此)。这使得 gRPC 的服务端流、双向流得以实现。
gRPC 的四大核心优势
- 高性能 Protobuf 二进制序列化比 JSON 快 5-10 倍,体积小 3-10 倍;HTTP/2 多路复用减少连接开销;服务间延迟更低,吞吐量更高。
- 强类型契约 .proto 文件是服务接口的唯一真相(Single Source of Truth)。编译时即发现接口不匹配,消除了文档与实现脱节的问题,团队协作更可靠。
- 多语言支持 从同一份 .proto 文件生成 Go、Python、Java、C++、Rust、TypeScript 等 10+ 语言的客户端/服务端代码。多语言微服务无缝互通,无需手写序列化逻辑。
- 原生流式传输 四种通信模式——Unary(一问一答)、服务端流、客户端流、双向流——覆盖所有实时通信场景,无需额外引入 WebSocket 或 SSE。
四种通信模式概览
// 1. Unary RPC(一问一答,最常用)
rpc GetUser(GetUserRequest) returns (UserResponse);
// 2. 服务端流(服务端推送多条消息)
rpc ListUsers(ListRequest) returns (stream UserResponse);
// 3. 客户端流(客户端发多条,服务端一次响应)
rpc UploadChunks(stream Chunk) returns (UploadResult);
// 4. 双向流(全双工,实时通信)
rpc Chat(stream Message) returns (stream Message);
适用场景
| 场景 | 推荐程度 | 理由 |
|---|---|---|
| 微服务内部通信 | 强烈推荐 | 性能最优,类型安全,多语言支持 |
| IoT 设备与云端 | 推荐 | 二进制协议节省带宽,适合弱网环境 |
| 移动端后端(BFF) | 推荐 | 减少数据传输量,降低移动端电量消耗 |
| 实时数据推送 | 推荐 | 流式模式天然适合实时场景 |
| 公开 API | 不推荐 | 浏览器不直接支持,调试不便 |
| 需要 CDN 缓存 | 不推荐 | POST 请求 + 二进制,CDN 无法缓存 |
安装工具链
安装 protoc 编译器
# macOS(Homebrew)
brew install protobuf
protoc --version # libprotoc 27.x
# Linux(Ubuntu)
sudo apt install -y protobuf-compiler
# 或从 GitHub Releases 下载二进制
# https://github.com/protocolbuffers/protobuf/releases
PB_REL="https://github.com/protocolbuffers/protobuf/releases"
curl -LO $PB_REL/download/v27.0/protoc-27.0-linux-x86_64.zip
unzip protoc-27.0-linux-x86_64.zip -d $HOME/.local
export PATH="$HOME/.local/bin:$PATH"
安装 Go 插件
# 安装 protoc-gen-go(生成消息结构体)
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
# 安装 protoc-gen-go-grpc(生成 gRPC 服务代码)
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# 确保 $GOPATH/bin 在 PATH 中
export PATH="$PATH:$(go env GOPATH)/bin"
# 验证
protoc-gen-go --version # protoc-gen-go v1.34.x
protoc-gen-go-grpc --version # protoc-gen-go-grpc 1.4.x
安装 Python 插件
# 创建虚拟环境(推荐)
python3 -m venv venv
source venv/bin/activate
# 安装 grpcio 运行时 + 代码生成工具
pip install grpcio grpcio-tools
# 验证
python3 -m grpc_tools.protoc --version
安装 buf(现代工具链推荐)
# macOS / Linux
brew install bufbuild/buf/buf
# 或直接下载
curl -sSL \
"https://github.com/bufbuild/buf/releases/latest/download/buf-$(uname -s)-$(uname -m)" \
-o /usr/local/bin/buf
chmod +x /usr/local/bin/buf
buf --version # 1.x.x
buf vs protoc:buf 是 protoc 的现代替代品,提供统一配置文件(buf.yaml)、lint 检查、breaking change 检测、BSR(Buf Schema Registry)远程依赖管理。新项目推荐使用 buf;遗留项目可以先用 protoc 熟悉流程。
名词解释
- IDL Interface Description Language(接口描述语言)。.proto 文件就是 gRPC 的 IDL,它独立于任何编程语言,描述了服务的输入输出数据结构和可调用的方法。
- 序列化 将内存中的数据结构(如 Go struct)转换为可网络传输的字节序列的过程。Protobuf 使用二进制编码;JSON 使用文本编码。反序列化是逆过程。
- 存根(Stub) 由 protoc 生成的客户端代码。它封装了底层网络通信细节,让调用者可以像调用本地方法一样调用远程服务。也叫"客户端存根"或"Client Stub"。
- 通道(Channel) 客户端与服务端之间的 HTTP/2 连接抽象。一个 Channel 可以复用多个 gRPC 调用(流),对应一个或多个底层 TCP 连接。创建 Channel 是开销较大的操作,应复用。
- Metadata gRPC 中类似 HTTP Header 的键值对,用于传递认证 Token、请求 ID、链路追踪 ID 等横切关注点(Cross-Cutting Concerns)。分为请求 Metadata 和尾部 Metadata。
- 拦截器(Interceptor) gRPC 的中间件机制,等同于 HTTP 框架中的 middleware。可以在 RPC 调用前后插入日志、认证、限流等逻辑,不影响业务代码。
本章小结:gRPC 通过 HTTP/2 + Protobuf 实现了高性能、强类型、多语言的远程调用。它不是 REST 的替代品,而是微服务内部通信的最佳选择。下一章我们深入 Protobuf 语法,掌握定义数据结构的核心技能。