官方设计文档

https://github.com/grpc/grpc-go/blob/master/Documentation/keepalive.md
gRPC在传输上发送http2 ping以检测连接是否断开。如果在一定时间内对方未确认ping,将关闭连接。请注意,仅当连接上没有活动时才需要执行ping操作。
Keepalive对于检测TCP级别的连接故障很有用。一种特殊情况是TCP连接丢失数据包(包括FIN)。需要使用系统TCP超时(可能是30分钟)来检测此故障。Keepalive将允许gRPC更快地检测到这个故障。
另一种用法(顾名思义)是保持连接处于活动状态。例如,L4代理被配置为杀死“空闲”连接。发送ping将使连接不“空闲”。
有关如何配置Keepalive的信息,请参见 https://godoc.org/google.golang.org/grpc/keepalive
我应该设置什么?
对于大多数用户而言,将客户端参数设置为拨号选项就足够了。
会发生什么?
(此处描述的行为特定于gRPC-go,在其他语言中可能会稍有不同。)
当连接上没有活动时(请注意,当没有消息发送时,正在进行的流将导致 没有活动),之后Time,客户端将发送ping命令,而服务器在收到ping命令后将发送ping ack。客户端将等待Timeout,并检查在此期间连接上是否有任何活动(Ping ack是一项活动)。
服务器端呢?
服务器也有类似的TimeTimeout设置为客户端。服务器还可以配置连接最大寿命。有关 详细信息,请参见服务器参数
执法政策
强制策略是服务器端的一项特殊设置,用于保护服务器免受恶意或行为不正常的客户端的侵害。
服务器发送ENHANCE_YOUR_CALM发送GOAWAY并在检测到不良行为时关闭连接:

  • 客户端发送太频繁的ping
  • 客户端在没有流的情况下发送ping命令,而服务器配置不允许这样做

type ClientParameters

ClientParameters用于在客户端设置keepalive参数。这些配置了客户端如何主动探测连接何时断开并发送ping信号,以便中介体能够感知连接的活动。确保这些参数是与服务器上的keepalive策略协调设置的,因为不兼容的设置可能导致关闭连接。

  1. type ClientParameters struct {
  2. //在一段时间后,如果客户端没有看到任何活动,它ping服务器,看看传输是否仍然是活动的。
  3. //如果设置小于10s,则使用最小值10s
  4. Time time.Duration // The current default value is infinity.
  5. //ping ack 20s之内未返回则认为连接已断开
  6. Timeout time.Duration // The current default value is 20 seconds.
  7. //如果是,客户端发送keepalive ping,即使没有活动的rpc。如果为false,当没有活动的rpc时,
  8. //时间和超时将被忽略,并且不会发送keepalive ping。
  9. PermitWithoutStream bool // false by default.
  10. }

type EnforcementPolicy

用于在服务器端设置keepalive实施策略。服务器将与违反此策略的客户端关闭连接。

  1. type EnforcementPolicy struct {
  2. // 客户端每次发送keepalive ping之间应该等待的最短时间
  3. MinTime time.Duration // The current default value is 5 minutes.
  4. // 如果是,服务器允许保持活的ping信号,即使没有活动的流(rpc)。
  5. //如果为false,客户端在没有活动流时发送ping,服务器将发送GOAWAY并关闭连接。
  6. PermitWithoutStream bool // false by default.
  7. }

type ServerParameters

在服务器端设置keepalive和max-age参数
服务端对每条链接执行的keepalive策略,因此如果建立很多的conn,且没有主动关闭,会导致server端大量goroutine堵塞在keepalive逻辑里
https://github.com/grpc/grpc-go/issues/1269

  1. type ServerParameters struct {
  2. //在这段时间之后,一个空闲连接将通过发送GoAway关闭。
  3. // 闲置时间是指最近一次未完成的rpc数量变为0或连接建立之后的时间。
  4. MaxConnectionIdle time.Duration // The current default value is infinity.
  5. // 连接在发送GoAway关闭之前,可能存在的最大时间长度
  6. MaxConnectionAge time.Duration // The current default value is infinity.
  7. // MaxConnectionAgeGrace是MaxConnectionAge之后的一个附加周期,在此之后连接将被强制关闭。
  8. MaxConnectionAgeGrace time.Duration // The current default value is infinity.
  9. // 在一段时间之后,如果服务器没有看到任何活动,它将ping客户机以查看传输是否仍然是活动的。
  10. // 如果设置在1s以下,则使用1s的最小值。
  11. Time time.Duration // The current default value is 2 hours.
  12. // ping ack 20s之内未返回则认为连接已断开
  13. // After having pinged for keepalive check, the server waits for a duration
  14. // of Timeout and if no activity is seen even after that the connection is
  15. // closed.
  16. Timeout time.Duration // The current default value is 20 seconds.
  17. }

遇到 grpc 客户端报错 rpc error: code = Unavailable desc = transport is closing,原因是连接长时间没有使用,被服务端断开,这种情况通过简单粗暴的重试策略可以解决,更加优雅的解决方案是增加保持连接策略
这个错误意味着RPC正在使用的连接被关闭,有很多可能的原因,包括:

  • 传输凭据配置错误,在握手时连接失败
  • 字节中断,可能是由于中间的代理
  • 服务器关闭
  • Keepalive参数会导致连接关闭,例如,如果您已将服务器配置为定期终止连接以触发DNS查找。如果是这种情况,您可能需要增加MaxConnectionAgeGrace,以允许更长的RPC调用完成。

client

  1. keep := keepalive.ClientParameters{
  2. Time:20*time.Second,
  3. Timeout:20*time.Second,
  4. PermitWithoutStream:true,
  5. }
  6. conn, err := grpc.Dial(address, grpc.WithInsecure(),grpc.WithKeepaliveParams(keep))

server

  1. var kaep = keepalive.EnforcementPolicy{
  2. MinTime: 5 * time.Second,
  3. PermitWithoutStream: true,
  4. }
  5. var kasp = keepalive.ServerParameters{
  6. MaxConnectionIdle: 15 * time.Second,
  7. MaxConnectionAge: 30 * time.Second,
  8. MaxConnectionAgeGrace: 5 * time.Second,
  9. Time: 5 * time.Second,
  10. Timeout: 1 * time.Second,
  11. }
  12. s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))

一个错误记录:https://ask.csdn.net/questions/1042789?sort=id