gRPC 设置有问题。获取间歇性 RPC 不可用错误

Problem with gRPC setup. Getting an intermittent RPC unavailable error

我有一个 grpc 服务器和客户端,大部分时间都按预期工作,但偶尔会出现 "transport is closing" 错误:

rpc error: code = Unavailable desc = transport is closing

我想知道是不是我的设置有问题。客户端非常基础

connection, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
pb.NewAppClient(connection)
defer connection.Close()

并且调用超时如

ctx, cancel := context.WithTimeout(ctx, 300*time.Millisecond)
defer cancel()

client.MyGRPCMethod(ctx, params)

我正在做的另一件事是检查连接以查看它是打开、空闲还是正在连接,如果是,则重新使用连接。否则重拨。

服务器没有发生任何特殊配置

grpc.NewServer()

我在设置 grpc client/server 时是否会犯任何常见错误?

我遇到了同样的问题 earlier this year。大约 15 分钟后,我让服务器关闭了连接。

我的解决方案是在我的 main 函数上用 grpc.Dial 创建我的 connection,然后在每个请求上创建 pb.NewAppClient(connection)。由于 connection 已经创建,延迟不是问题。请求完成后我关闭了客户端。

One other thing I'm doing is checking the connection to see if it's either open, idle or connecting, and reusing the connection if so. Otherwise, redialing.

grpc 将为您管理您的连接,并在需要时重新连接,因此除非您有非常特殊的需求,否则您永远不需要在创建后对其进行监控。

"transport is closing" 发生的原因有很多;请在我们的常见问题解答中查看相关问题,如果您仍有疑问,请告诉我们:https://github.com/grpc/grpc-go#the-rpc-failed-with-error-code--unavailable-desc--transport-is-closing

经过多次搜索,我终于找到了一个可以接受且合乎逻辑的解决方案。

根本原因是这样的:底层TCP连接突然关闭,但是gRPC Client和Server都不是'notified'事件.

挑战是多层次的:

  • 内核对 TCP 套接字的管理
  • 任何中介load-balancers/reverse-proxies(由云提供商或其他方式)以及他们如何管理 TCP 套接字
  • 您的应用层本身及其网络要求 - 它是否可以为未来的请求重用相同的连接

我的解决方案非常简单:

server = grpc.NewServer(
    grpc.KeepaliveParams(keepalive.ServerParameters{
        MaxConnectionIdle: 5 * time.Minute,           // <--- This fixes it!
    }),
)

这确保 gRPC 服务器在内核或中间服务器突然终止之前自行优雅地关闭底层 TCP 套接字(AWS 和 Google 云负载均衡器的超时时间都超过 5 分钟)。

您会在这里发现的额外好处是,在您使用多个连接的任何地方,忘记关闭连接的客户端引入的任何泄漏也不会影响您的服务器。

我的 $0.02: 不要盲目相信任何组织(甚至 Google)设计和维护 API 的能力。这是默认错误的经典案例。