gRPC 四种 RPC 通信模式
这四种流式通信模式,本质上是由 客户端发起的请求流 和 服务端返回的响应流 组合而成的。核心区别在于发送或接收消息的次数。
我用一张表帮你快速理清,再逐一深入讲解:
| 模式 | 客户端请求 | 服务端响应 | 适用场景 |
|---|---|---|---|
| 1. 一元 RPC (Unary) | 1 条 | 1 条 | 普通接口调用,如同步函数 |
| 2. 服务端流式 (Server Streaming) | 1 条 | N 条(流) | 服务端持续推送数据 |
| 3. 客户端流式 (Client Streaming) | N 条(流) | 1 条 | 客户端批量上传或持续上报 |
| 4. 双向流式 (Bidirectional Streaming) | N 条(流) | N 条(流) | 实时全双工交互 |
1. 一元 RPC (Unary RPC)
这是最“经典”的 RPC 模式,和普通的 HTTP 请求/响应完全一致。
- 行为:客户端发送一个请求,阻塞等待,直到服务端返回一个响应。
- proto 定义:不加
stream关键字。rpc GetUser (UserIdRequest) returns (UserResponse); - 典型场景:登录验证、获取用户详情、订单查询等常规读写操作。
2. 服务端流式 RPC (Server Streaming RPC)
客户端发送一个请求,服务端会返回一个数据流(可以持续发送多条消息)。
- 行为:客户端发起请求后,会持续监听(非阻塞),服务端可以多次调用
Send()方法发送数据,直到发送完毕并告知客户端结束。 - proto 定义:在
returns前加stream。rpc GetStockPrice (StockRequest) returns (stream StockPrice); - 典型场景:
- 实时行情:客户端请求某只股票,服务端持续推送最新股价。
- 大日志导出:客户端请求导出一个月的大文件日志,服务端分块流式返回,避免内存溢出。
- 进度推送:客户端发起长耗时任务(如视频转码),服务端通过流实时返回当前进度百分比。
3. 客户端流式 RPC (Client Streaming RPC)
客户端发送一个数据流到服务端,服务端处理完所有数据后,只返回一个最终响应。
- 行为:客户端可以多次调用
Send()发送数据,发送完成后调用CloseAndRecv()告知服务端“我发完了”。服务端接收完所有数据,处理完毕后返回一个响应。 - proto 定义:在
request前加stream。rpc UploadFile (stream FileChunk) returns (UploadStatus); - 典型场景:
- 大文件上传:客户端将大文件切成多个数据块(Chunk)分片上传。
- 物联网数据上报:传感器设备不断向服务器上报温度、湿度数据,服务器汇总计算后返回一个平均指标。
4. 双向流式 RPC (Bidirectional Streaming RPC)
这是最强大的模式。客户端和服务端各自独立地维持一个读写数据流,双方可以同时发送和接收消息。
- 行为:调用开始后,双方维持长连接。客户端和服务端的发送和接收完全解耦且异步(顺序由业务逻辑决定,但消息顺序在各流内是保序的)。
- proto 定义:在
request和returns前都加stream。rpc Chat (stream ChatMessage) returns (stream ChatMessage); - 典型场景:
- 实时聊天室:用户发送消息的同时,实时接收其他人发送的消息。
- 实时游戏同步:客户端发送玩家操作指令,服务端推送其他玩家的位置状态。
- 分布式协同:两个微服务之间建立长连接,实时交换监控状态或配置变更通知。
⚠️ 实现原理上的一点重要补充
理解双向流时,要记住一个底层特性:双向流并不是一条“双绞线”,而是两条独立的“单向流水线”(基于 HTTP/2 的多路复用)。这意味着:
- 服务端可以等到接收完所有客户端消息再开始发送响应,也可以在刚收到第一条请求时就开始发送响应,完全不依赖于客户端的发送进度。
- 每条流内的消息顺序有保证(先发的先到),但客户端流和服务端流之间的消息顺序无法相互保证。
如何选择?
- 服务间同步调用:直接用 一元 RPC,简单高效。
- 数据量过大:用 服务端流(拉取大数据)或 客户端流(上传大数据)。
- 需要实时推送:用 服务端流(如推送新闻)或 双向流(如即时通讯)。
- 两端都需要随时发送数据:请毫不犹豫选择 双向流式。