gRPC从0到1系列【15】
文章目录
- 六、双向流式RPC (Bidirectional Streaming RPC)
- 6.1 概述
- 6.1.1 什么是双向流式 RPC?
- 6.1.2 为什么需要双向流式 RPC?
- 6.1.3 工作原理与 StreamObserver 角色
- 6.1.4 流程简图
六、双向流式RPC (Bidirectional Streaming RPC)
6.1 概述
6.1.1 什么是双向流式 RPC?
双向流式 RPC 是 gRPC 支持的四种通信模式之一。在这种模式下:
- 客户端:可以向服务端发送一个数据流(多个请求消息)。
- 服务端:也可以向客户端发送一个数据流(多个响应消息)。
这两个数据流是完全独立的,可以并行发送,也可以交替发送。通信双方都可以随时向对方发送数据,直到各自的流结束。
你可以把它想象成两个人打电话:
- 客户端和服务端就像电话两端的两个人。
- 任何一方都可以随时说话(发送数据),不需要等对方说完。
- 一方可以连续说好几句话(连续发送多个
onNext
)。 - 当一方说完所有想说的话后,可以告诉对方 “我说完了”(调用
onCompleted
),但仍然可以继续听对方说。 - 只有当双方都 “说完了” 并且 “挂了电话”,整个通话(RPC)才正式结束。
6.1.2 为什么需要双向流式 RPC?
双向流式 RPC 特别适用于需要实时、低延迟、双向数据交换的场景。
- 实时聊天 / 即时通讯 (IM):
- 场景描述:用户 A 和用户 B 通过聊天应用交流。A 发送一条消息,B 立即收到;B 回复一条消息,A 也立即收到。
- 为什么适合:通信是双向且实时的,双方都需要持续发送和接收消息。
- 实时游戏:
- 场景描述:在一个多人在线游戏中,每个玩家的操作(移动、射击)需要实时广播给其他玩家,同时也需要接收其他玩家的操作。
- 为什么适合:游戏状态需要在客户端和服务器之间高频、双向地同步,任何延迟都会影响游戏体验。
- 股票 / 加密货币行情推送:
- 场景描述:客户端订阅一组股票代码,服务端实时推送这些股票的价格变动。同时,客户端也可以随时发送新的订阅或取消订阅请求。
- 为什么适合:服务端到客户端的数据流是主要的,但客户端需要有能力动态调整订阅列表,这构成了反向的数据流。
- 远程过程调用的流式参数和流式返回值:
- 场景描述:一个复杂的计算任务,客户端需要向服务端流式提供大量输入数据(如机器学习模型的训练数据),同时服务端也可以在计算过程中流式返回中间结果或日志。
- 为什么适合:实现了 “边输入边处理边输出” 的高效模式,避免了等待所有数据输入完毕才开始处理。
优势:
- 真正的全双工通信:充分利用 HTTP/2 的多路复用和全双工特性,实现双方数据的并行传输。
- 低延迟和高吞吐:数据可以在准备好后立即发送,无需等待对方响应,极大地降低了端到端延迟。
- 极高的灵活性:通信模式完全由应用层逻辑决定,可以是请求 - 响应式、广播式、或任何自定义的交互模式。
6.1.3 工作原理与 StreamObserver 角色
双向流式 RPC 的核心仍然是 StreamObserver
接口。理解它在通信双方的双重角色是掌握该模式的关键。
✅ StreamObserver 角色分析:
- 客户端 (Client):
- requestObserver: 客户端调用 RPC 方法后,gRPC 框架立即返回一个
StreamObserver
。客户端通过调用这个 requestObserver 的onNext()
方法来发送自己的流式请求数据。 - responseObserver: 客户端在发起 RPC 调用时,需要自己实现并传入一个
StreamObserver
。这个 responseObserver用于接收服务端发来的流式响应数据(通过onNext()
)以及 RPC 的完成或错误通知。
- requestObserver: 客户端调用 RPC 方法后,gRPC 框架立即返回一个
- 服务端 (Server):
- requestObserver(隐式实现): 服务端需要实现 gRPC 生成的服务接口。在双向流式方法中,服务端的实现会接收一个 StreamObserver作为参数。这个
StreamObserver
是服务端用来 “观察” 客户端发送过来的流式请求的。 - responseObserver(返回的): 服务端的方法实现需要返回一个
StreamObserver
。这个StreamObserver
是服务端用来向客户端发送流式响应的。服务端通过调用它的onNext()
方法来发送数据。
- requestObserver(隐式实现): 服务端需要实现 gRPC 生成的服务接口。在双向流式方法中,服务端的实现会接收一个 StreamObserver作为参数。这个
关键点:客户端和服务端都同时扮演着 “生产者” 和 “消费者” 的角色。它们各自拥有一个用于发送的 StreamObserver
和一个用于接收的 StreamObserver
。