4. gRPC基础入门
在微服务架构中,服务间通信的效率和可靠性至关重要。gRPC 作为高性能、开源的远程过程调用(RPC)框架,已成为云原生生态中的通信标准。本章将系统介绍 gRPC 的核心概念、序列化基础以及四种通信模式,为后续的健康检查与可用性保障方案打下坚实基础。
4.1 gRPC 简介
gRPC 由 Google 开发,基于 HTTP/2 协议传输,使用 Protocol Buffers 作为接口定义语言(IDL)和序列化工具。其核心优势包括:
- 高性能:基于 HTTP/2 的多路复用、头部压缩和二进制帧传输,显著降低延迟和带宽消耗。
- 跨语言:支持 C++、Java、Go、Python、Node.js 等十余种语言,服务定义与实现解耦。
- 强类型:通过 .proto 文件定义服务和消息结构,编译生成客户端和服务端桩代码,避免运行时类型错误。
- 流式通信:原生支持四种通信模式,适应实时推送、大数据传输等场景。
4.2 Protocol Buffers 基础
Protocol Buffers(简称 Protobuf)是 gRPC 的默认序列化协议。它通过 .proto 文件定义数据结构,并使用编译器(protoc)生成各语言的代码。
4.2.1 消息定义
以下是一个典型的 .proto 文件示例,定义了一个简单的用户服务和健康检查消息:
syntax = "proto3";
package healthcheck;
// 健康检查请求
message HealthCheckRequest {
string service_name = 1;
}
// 健康检查响应
message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
SERVICE_UNKNOWN = 3;
}
ServingStatus status = 1;
}
// 健康检查服务
service Health {
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}
4.2.2 字段类型与编号
| 类型 | 说明 | 示例 |
|---|---|---|
| 标量类型 | int32、int64、float、double、bool、string、bytes | int32 id = 1; |
| 枚举 | 预定义常量集合 | enum Status { OK = 0; ERROR = 1; } |
| 嵌套消息 | 消息内部定义其他消息 | message Result { string msg = 1; } |
| repeated | 可变长度数组(列表) | repeated string tags = 3; |
| map | 键值对映射 | map<string, int32> scores = 4; |
4.3 gRPC 四种通信模式
gRPC 基于 HTTP/2 的流式特性,定义了四种 RPC 通信模式。理解这些模式是设计微服务接口的关键。
4.3.1 模式对比总览
| 模式 | 请求 | 响应 | 典型场景 |
|---|---|---|---|
| Unary(一元) | 单个请求 | 单个响应 | 查询、写入、认证 |
| Server Streaming(服务端流) | 单个请求 | 流式响应 | 日志推送、监控数据流 |
| Client Streaming(客户端流) | 流式请求 | 单个响应 | 批量上传、聚合计算 |
| Bidirectional Streaming(双向流) | 流式请求 | 流式响应 | 实时聊天、协同编辑 |
4.3.2 四种模式详解
1. Unary RPC(一元 RPC)
客户端发送一个请求,服务端返回一个响应。这是最基础的 RPC 模式,行为类似传统 HTTP 请求-响应模型。
// .proto 定义
rpc GetUser(GetUserRequest) returns (User);
// 客户端调用(Go 示例)
user, err := client.GetUser(ctx, &pb.GetUserRequest{UserId: 123})
2. Server Streaming RPC(服务端流 RPC)
客户端发送一个请求,服务端返回一个消息流。客户端持续读取流直到结束。适用于服务端需要推送大量数据的场景。
// .proto 定义
rpc SubscribeEvents(SubscribeRequest) returns (stream Event);
// 客户端读取流
stream, _ := client.SubscribeEvents(ctx, &pb.SubscribeRequest{Topic: "orders"})
for {
event, err := stream.Recv()
if err == io.EOF { break }
// 处理 event
}
3. Client Streaming RPC(客户端流 RPC)
客户端发送一个消息流,服务端在接收完所有消息后返回一个响应。适用于客户端需要上传大量数据的场景。
// .proto 定义
rpc UploadLogs(stream LogEntry) returns (UploadSummary);
// 客户端发送流
stream, _ := client.UploadLogs(ctx)
for _, log := range logs {
stream.Send(&pb.LogEntry{Message: log})
}
summary, _ := stream.CloseAndRecv()
4. Bidirectional Streaming RPC(双向流 RPC)
客户端和服务端可以独立地发送和接收消息流,两者是异步并行的。适用于实时交互场景。
// .proto 定义
rpc Chat(stream ChatMessage) returns (stream ChatMessage);
// 客户端同时发送和接收
stream, _ := client.Chat(ctx)
go func() {
for _, msg := range messages {
stream.Send(&pb.ChatMessage{Content: msg})
}
stream.CloseSend()
}()
for {
reply, err := stream.Recv()
if err == io.EOF { break }
// 处理回复
}
4.4 gRPC 通信模式架构图
下图展示了四种通信模式在客户端与服务端之间的数据流关系:
4.5 模式选择决策流程
在实际微服务设计中,应根据业务需求选择合适的通信模式。以下决策流程可帮助快速判断:
4.6 本章小结
- gRPC 基于 HTTP/2 和 Protocol Buffers,提供高性能、跨语言的 RPC 通信能力。
- Protocol Buffers 通过 .proto 文件定义消息和服务,支持标量、枚举、嵌套、repeated 和 map 等类型。
- 四种通信模式(Unary、Server Streaming、Client Streaming、Bidirectional Streaming)覆盖了从简单请求-响应到复杂实时交互的全部场景。
- 选择通信模式时,应首先判断请求和响应的数量关系,再结合业务场景确定最合适的模式。