我有一个使用两个双向流的 gRPC 客户端。由于目前未知的原因,当我们每小时发送一次 keepAlive ping 时,两个流上都会调用带有 statusRuntimeException
的 onError。
为了处理重新连接,我在 java 伪代码中实现了以下重试机制。我会在评论中根据需要澄清任何内容。
该机制如下所示:
onError() {
retrySyncStream();
}
void retrySyncStream() {
// capture the current StreamObserver
previousStream = this.StreamObserver;
// open a new stream
streamObserver = bidiStub.startStream(responseObserver);
waitForChannelReady(); // <-- simplified version, we use the gRPC notification listener
previousStream.onCompleted(); // <-- called on notify of channel READY
}
尽管我们尝试关闭旧流,但服务器端我们看到 2 个 HA 节点上打开了 2 个连接。我无法控制服务器端的任何内容,我只需要处理客户端上的重新连接逻辑。
首先,在收到 StatusRuntimeException 后抛弃旧的 StreamObserver 是常见做法吗?我这样做的原因是因为我们有一个模拟服务器 Spring Boot 应用程序,我们用它来测试我们的客户端。当我强制关闭 (Ctl-c) Spring Boot 服务器应用程序并再次启动它时,客户端无法使用原始 StreamObserver,它必须通过调用 gRPC bidi 流 API 调用来创建一个新的 StreamObserver。
根据我在网上读到的内容,人们说不要放弃托管 channel ,但是流观察者怎么样,并确保多个流不会被错误地打开? 谢谢。
最佳答案
当 StreamObserver 出现错误时,RPC 就终止了。抛弃它是合适的。
当您重新创建流时,请考虑如果服务器出现问题会发生什么情况。一般来说,你会在某个地方设置指数退避。对于双向流情况,如果客户端收到服务器的响应,gRPC 中的几种情况往往会重置退避。
由于两个流同时死亡,听起来 TCP 连接已死亡。不幸的是,在 TCP 中,您必须在连接上发送数据才能得知它已失效。当客户端得知连接已断开时,它会得知这是因为它无法使用该连接向 HA 代理发送数据。这意味着 HA 必须单独发现连接已断开。服务器端 keepalive 可以对此有所帮助,尽管 HA 处的 TCP keepalive 也可能是有保证的。
关于java - gRPC 客户端重新连接逻辑导致服务器端打开重复的流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71851301/