gRPC流式服务与高并发通信 - 第2节
2. gRPC基础入门
gRPC 是由 Google 开源的高性能、跨语言的远程过程调用(RPC)框架,基于 HTTP/2 协议传输,默认使用 Protocol Buffers(protobuf)作为接口定义语言(IDL)与序列化工具。它允许客户端像调用本地函数一样直接调用另一台服务器上的方法,屏蔽了网络通信、序列化、反序列化等底层细节。
传统 RPC 框架(如 Java RMI、XML-RPC)通常存在语言绑定强、传输效率低、协议不统一等问题。gRPC 通过以下设计解决了这些痛点:
- HTTP/2 多路复用:单个连接支持并发请求,降低延迟与连接开销。
- Protocol Buffers 二进制序列化:体积小、解析快,比 JSON 快 3~10 倍。
- 语言中立:通过 protoc 编译器生成 11+ 种语言的客户端/服务端代码。
- 四种通信模式:支持一元、服务端流、客户端流、双向流,满足微服务复杂交互场景。
核心定义:gRPC = HTTP/2 + Protocol Buffers + 服务定义 + 自动代码生成。它不是一个简单的 RPC 库,而是一套完整的微服务通信基础设施。
2.2 gRPC 与 REST 对比:为什么微服务需要 gRPC?
REST 是微服务架构中最常见的通信风格,但 gRPC 在高性能、低延迟、强类型场景下具有显著优势。下表从多个维度进行对比:
| 对比维度 | REST (HTTP/1.1 + JSON) | gRPC (HTTP/2 + Protobuf) |
|---|---|---|
| 传输协议 | HTTP/1.1,文本格式 | HTTP/2,二进制帧 |
| 序列化 | JSON(文本,冗余大) | Protocol Buffers(二进制,紧凑) |
| 接口定义 | 无强制契约,依赖文档 | .proto 文件,强类型契约 |
| 代码生成 | 手动编写客户端 | 自动生成客户端/服务端 Stub |
| 通信模式 | 请求-响应(一元) | 一元、服务端流、客户端流、双向流 |
| 浏览器支持 | 原生支持 | 需 gRPC-Web 代理 |
| 适用场景 | 外部 API、Web 前端、简单 CRUD | 内部微服务、实时流、IoT、低延迟系统 |
选型建议:对外暴露的 API 网关层建议使用 REST,便于浏览器和第三方集成;内部微服务间通信优先使用 gRPC,以获得性能与类型安全优势。
下图展示了 gRPC 与 REST 在微服务架构中的典型分工:
2.3 gRPC 核心概念:Protocol Buffers、Service、Stub
2.3.1 Protocol Buffers:接口定义语言与序列化引擎
Protocol Buffers(简称 protobuf)是 gRPC 的基石,承担两个角色:接口定义语言(IDL) 和 高效序列化引擎。开发者通过编写 .proto 文件定义消息结构和服务接口,然后使用 protoc 编译器生成目标语言的代码。
一个典型的 .proto 文件结构如下:
syntax = "proto3";
package order.v1;
// 定义订单消息
message OrderRequest {
string order_id = 1;
int32 user_id = 2;
repeated string item_ids = 3;
}
message OrderResponse {
string status = 1;
string message = 2;
}
// 定义订单服务
service OrderService {
rpc CreateOrder(OrderRequest) returns (OrderResponse);
rpc StreamOrderStatus(OrderRequest) returns (stream OrderResponse);
}
protobuf 的核心优势:
- 字段编号:每个字段使用唯一编号(如
=1),而非字段名,序列化时体积极小。 - 向后兼容:新增字段不影响旧版本客户端,只需分配新编号。
- 多语言生成:一条
protoc命令即可生成 Python、Go、Java 等语言的代码。
2.3.2 Service:定义远程调用契约
在 .proto 文件中,service 关键字定义了一组 RPC 方法,每个方法指定输入消息类型和输出消息类型。gRPC 支持四种服务方法模式:
| 模式 | 定义语法 | 典型场景 |
|---|---|---|
| 一元(Unary) | rpc Foo(Request) returns (Response); |
传统请求-响应,如用户登录 |
| 服务端流 | rpc Foo(Request) returns (stream Response); |
实时推送,如订单状态更新 |
| 客户端流 | rpc Foo(stream Request) returns (Response); |
批量上传,如日志收集 |
| 双向流 | rpc Foo(stream Request) returns (stream Response); |
实时聊天、协同编辑 |
注意:流式通信是 gRPC 区别于 REST 的核心能力。在微服务架构中,服务端流和双向流常用于事件驱动、实时数据同步等场景,能显著降低轮询带来的网络开销。
2.3.3 Stub:客户端与服务端的通信代理
Stub(存根)是 gRPC 自动生成的代码,分为客户端 Stub 和服务端 Stub:
- 客户端 Stub:封装了网络调用细节,开发者只需调用 Stub 方法即可发起 RPC 请求。gRPC 提供两种客户端 Stub:
- 阻塞式 Stub:同步等待服务端响应,适合简单请求。
- 非阻塞式 Stub:基于 Future 或回调,适合并发场景。
- 服务端 Stub:生成服务端骨架代码,开发者只需实现业务逻辑,框架自动处理请求接收、序列化、响应发送。
下图展示了 gRPC 核心概念之间的关系:
2.3.4 三者协作流程
- 定义契约:在
.proto文件中编写消息结构(Message)和服务接口(Service)。 - 生成代码:运行
protoc编译器,生成客户端 Stub 和服务端 Stub 代码。 - 实现服务端:继承服务端 Stub 基类,实现业务逻辑方法。
- 调用客户端:创建客户端 Stub 实例,像调用本地函数一样调用远程方法。
- 通信传输:gRPC 框架自动将请求序列化为 Protobuf 二进制格式,通过 HTTP/2 帧传输,服务端反序列化后执行逻辑并返回响应。
实践要点:在 Python 中,使用
该命令会生成
grpcio 和 grpcio-tools 包。生成命令示例:python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. order.proto该命令会生成
order_pb2.py(消息类)和 order_pb2_grpc.py(Stub 类)。