我们有一个公共的gRPC接口。我们有一个客户端,它基于为每个请求创建一个连接(通道)的REST范例来使用我们的API。我们怀疑一旦发出请求,他们就不会关闭此通道。
在服务器端,所有功能都正常运行了一段时间,然后似乎有些功能耗尽了。请求在服务器上备份并且不被处理-这会导致我们的代理超时并发送不可用的响应。重新启动服务器解决了这个问题,我可以在服务器关闭时在日志中看到备份的请求被刷新。
不幸的是,似乎没有办法监控服务器端正在发生的事情并修剪这些连接。我们有以下keep alive设置,但它们似乎没有影响:
grpc.KeepaliveParams(keepalive.ServerParameters{
MaxConnectionIdle: time.Minute * 5,
MaxConnectionAge: time.Minute * 15,
MaxConnectionAgeGrace: time.Minute * 1,
Time: time.Second * 60,
Timeout: time.Second * 10,
})我们还尝试将MaxConcurrentStreams从默认的250升级到1000,但是pod是我们可以在服务器端监控通道创建、使用和破坏的任何方法-如果只是为了证明或反驳客户端的消费方法导致了问题。
详细日志记录没有帮助,因为它似乎只记录服务器上的客户端活动(即,服务器使用发布/订阅并作为客户端进行日志记录)。我也看过一个通道,但我们有共同的TLS身份验证,我一直没有成功地让它在我们的生产pod上工作。
我们已经指示我们的客户使用单一渠道,如果这是不可能的,关闭他们正在创建的渠道,但他们是一家公司,行动非常缓慢。我们也无法检查他们的代码。我们只知道他们是用dotnet开发的。我们也无法复制以类似数量运行我们自己的go客户端的行为。
发布于 2021-04-26 04:27:31
这个漏洞是MaxConnectionIdle,它总是会在指定的时间后创建一个新的http2server,最终你的服务会因为goroutine泄漏而崩溃。
删除MaxConnectionIdle和MaxConnectionAge,然后(最好)确保ServerParameters和ClientParameters使用相同的Time和Timeout。
const (
Time = 5 * time.Second // wait X seconds, then send ping if there is no activity
Timeout = 5 * time.Second // wait for ping back
)
// server code...
grpc.KeepaliveParams(keepalive.ServerParameters{
Time: Time,
Timeout: Timeout,
MaxConnectionAgeGrace: 10 * time.Second,
})
// client code...
grpc.WithKeepaliveParams(keepalive.ClientParameters{
Time: Time,
Timeout: Timeout,
PermitWithoutStream: true,
}),https://stackoverflow.com/questions/65272088
复制相似问题