gRPC 客户端重新连接逻辑导致在服务器端打开重复流

gRPC client side reconnection logic causing duplicate streams to be opened server side

我有一个使用两个双向流的 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 启动应用程序,我们用它来测试我们的客户端。当我强制关闭 (Ctl-c) spring 引导服务器应用程序并再次启动它时,客户端无法使用原始的 StreamObserver,它必须通过调用 gRPC bidi 创建一个新的流 API 调用。

根据我在网上阅读的内容,人们说不要放弃托管频道,但是流观察器如何,并确保不会错误地打开多个流? 谢谢

当 StreamObserver 出错时,RPC 已死。抛弃它是合适的。

当您 re-create 流时,请考虑如果服务器出现问题会发生什么情况。通常,您会在某处设置指数退避。对于 bidi 流式传输案例,如果客户端收到来自服务器的响应,gRPC 中的一些案例往往会重置退避。

由于两个流一起终止,听起来 TCP 连接已终止。不幸的是,在 TCP 中你必须发送连接才能知道它已经死了。当客户端得知连接已断开时,它了解到因为它无法 使用该连接发送到 HA 代理。这意味着 HA 必须单独发现连接已断开。 Server-side keepalive 可以帮助解决这个问题,尽管 HA 的 TCP keepalive 可能也是必要的。