我有一个grpc服务器和客户端,大多数时候都能正常工作,但是偶尔会收到“传输正在关闭”错误:
rpc error: code = Unavailable desc = transport is closing
Run Code Online (Sandbox Code Playgroud)
我想知道我的设置是否有问题。客户端很基础
connection, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
pb.NewAppClient(connection)
defer connection.Close()
Run Code Online (Sandbox Code Playgroud)
并以类似超时的方式拨打电话
ctx, cancel := context.WithTimeout(ctx, 300*time.Millisecond)
defer cancel()
client.MyGRPCMethod(ctx, params)
Run Code Online (Sandbox Code Playgroud)
我正在做的另一件事是检查连接以查看它是处于打开,空闲还是正在连接状态,如果有则重新使用该连接。否则,请重拨。
服务器没有任何特殊配置
grpc.NewServer()
Run Code Online (Sandbox Code Playgroud)
设置我可能正在设置的grpc客户端/服务器是否存在任何常见错误?
经过大量的搜索,我终于找到了可以解决该问题的合理方法。
根本原因是这样的:底层的TCP连接突然关闭,但是gRPC客户端和服务器均未“通知”该事件。
挑战来自多个层面:
我的解决方案非常简单:
server = grpc.NewServer(
grpc.KeepaliveParams(keepalive.ServerParameters{
MaxConnectionIdle: 5 * time.Minute, // <--- This fixes it!
}),
)
Run Code Online (Sandbox Code Playgroud)
这样可以确保gRPC服务器在内核或中间服务器突然中断之前(AWS和Google Cloud Load Balancers的超时都超过5分钟),先自行正常关闭基础TCP套接字。
您还将在这里找到的额外好处是,在使用多个连接的任何地方,客户端导致的忘记关闭连接的任何泄漏也不会影响您的服务器。
我的0.02美元:不要盲目相信任何组织(甚至是Google)设计和维护API的能力。这是defaults-gone-wrong的经典案例。
我正在做的另一件事是检查连接以查看它是否处于打开、空闲或连接状态,如果是,则重新使用该连接。否则,重拨。
grpc 将为您管理您的连接,并在需要时重新连接,因此您不需要在创建它后监视它,除非您有非常具体的需求。
“交通关闭”的发生有许多不同的原因;请参阅我们的常见问题解答中的相关问题,如果您仍有疑问,请告诉我们:https://github.com/grpc/grpc-go#the-rpc-failed-with-error-code--unavailable-desc--运输正在关闭