总结:如果客户端通道处于某种READY状态并且网络断开,则通道将变得不可用,并且一旦重新建立网络连接,客户端将不会尝试重新连接到服务器。通道不会从READY状态转换TRANSIENT_FAILURE为DEADLINE_EXCEEDED错误(由我的客户端应用程序设置的截止日期)。
您使用的是什么版本的 gRPC 和什么语言?
1.17.2 版本 1.11.x C++ 相同问题体验
什么操作系统(Linux、Windows 等)和版本?
在 Ubuntu 16.04 上运行的客户端。运行 Windows Enterprise 的服务器。
你做了什么?
服务器和客户端都在连接的网络上启动。我可以成功拨打电话并接收来自服务器的响应。当网络关闭时,服务器会收到"Disconnected client - Endpoint read failed"错误消息。此调试消息中的其他一些相关字段 - "grpc_status":14 (UNAVAILABLE), "occured_during_write":0, "description":"An established connection was aborted by the software in your host machine"。
在网络断开时,客户端根本不打印任何日志(使用GRPC_TRACE=connectivity_state,call_error,op_failure,server_channel,client_channel,channel GRPC_VERBOSITY=DEBUG)。
再次打开网络后,服务器和客户端都没有日志记录。尝试使用客户端进行调用(发送启动请求)会导致重复DEADLINE_EXCEEDED错误。此时关闭网络连接不会导致服务器端"Disconnected client"错误。
客户端上下文设置为使用截止日期(测试时间为 2 秒和 10 秒)。在这种情况下使用同步调用。
代码片段:
/rpc_service.proto
syntax = "proto3";
import "google/rpc/status.proto";
message RpcRequest {
}
message RpcResponse {
}
service RpcService{
rpc Call(RpcRequest) returns (RpcResponse);
}
Run Code Online (Sandbox Code Playgroud)
/client.cc
初始化:
std::unique_ptrRpcService::Stub stub_ = RpcService::NewStub(::grpc::CreateChannel(
server_endpoint, ::grpc::InsecureChannelCredentials()));
Run Code Online (Sandbox Code Playgroud)
发送 rpc 请求:
::grpc::ClientContext context;
context.set_deadline(
gpr_time_from_micros(call_timeout_.InMicroseconds(), GPR_TIMESPAN));
RpcRequest request;
RpcResponse response;
::grpc::Status grpc_status = stub_->Call(&context, request, &response);
Run Code Online (Sandbox Code Playgroud)
/server.cc
grpc::ServerBuilder builder;
builder.AddListeningPort(endpoint, ::grpc::InsecureServerCredentials());
builder.RegisterService(&rpc_service);
std::unique_ptrgrpc::Server grpc_server_ = builder.BuildAndStart();
Run Code Online (Sandbox Code Playgroud)
你期待看到什么?
客户端应在网络重置后成功调用。
你看到了什么?
客户端无法从服务器接收响应。
关于您的项目/环境,我们还应该了解什么?
当重新建立网络连接并且客户端无法收到服务器的响应时,tcpdump 会捕获客户端发送的一些数据包。在网络打开的情况下启动客户端和服务器,然后在尝试调用之前拔掉网络不会导致任何错误消息。这与在网络断开连接的情况下启动客户端和服务器时的结果相同。一旦尝试调用,客户端将从IDLEto转换CONNECTING,然后开始在CONNECTINGandTRANSIENT_FAILURE状态之间来回反弹(尝试使用指数退避重新连接),直到重新建立连接。
如果客户端在连接网络的情况下启动,但不发送请求并且网络断开连接,则服务器不会收到断开连接的客户端错误。在进行呼叫之前,客户端将停留在"IDLE".
如果客户端已初始化并在断开连接的网络上进行呼叫,则客户端将进入一种CONNECTING状态(指数退避最多 2 分钟,客户端将处于该TRANSIENT_FAILURE状态)。一旦网络连接好,下一次通道进入CONNECTING状态时会重新建立连接,客户端进入READY状态。此后,每次调用都会成功,直到网络重置。在客户端处于某种READY状态后断开网络连接不会使客户端脱离READY状态。
总结:在调用之前,"IDLE"无论网络状态如何,客户端都会保持一种状态。一旦发出呼叫,客户端将尝试通过进入该CONNECTING状态来建立连接。如果没有找到连接,它将在CONNECTING和TRANSIENT_FAILURE状态之间转换反弹。一旦找到连接,客户端将进入一种READY状态。从这里开始,如果连接丢失,客户端将不会CONNECTING再次尝试进入状态。
与我遇到的类似问题(已关闭):
https://github.com/grpc/grpc/issues/16974
已知修复:
在每次通话时创建一个新频道。
失败的修复尝试:
Set GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA = 0
Run Code Online (Sandbox Code Playgroud)
问题:
网络重置后,客户端是否可以使用已创建的通道?
网络重置时是否必须重新启动通道?
注意:我在grpc github上开了一个票,5天了还没有收到回复,所以我也在这里发帖。链接到 grpc github 问题:https : //github.com/grpc/grpc/issues/18554
| 归档时间: |
|
| 查看次数: |
1197 次 |
| 最近记录: |