缘起: grpc-client 连接 grpc-server后,空闲连接的情况下,server端会每隔15s向client发送一个keepalive数据包; 从grpc-server的配置中没有找到这个15s的配置,有的只是一个2小时发送一次的应用层的ping包。为啥呢?
分析:
- 该数据包可能是系统自己发送的,查看一下sysctl -a|grep tcp |grep keepalive 如下:
按照这个配置,应该是75s一次才对,和实际的15s不符;难道不是系统发出来的?- kill -19 PID后,发现间隔15s的数据包依然发送,说明肯定是系统发出来的
- 由于MacOS上的netstat 无法查看连接的Timer信息,于是使用Linux进行测试,发现keepalive的timer果然是从15s递减至0后就会发送该数据包(这里还发现当时间小于10s时,ss显示的时间单位是错的,把s写成了ms)。
- 一定是golang设置了一个和系统默认值不一样的keepalive; 那么是在什么时候设置的呢?从server端的Accept看起吧,发现Listen的时候有一个无法自定义的ListenerConfig,这里面有
@ net/dialog.go
Listen的时候,KeepAlive是0值,但是在newTcpConn的时候,检测如果是0值,就参考下面的默认值。
@ net/tcpsock.go
其实,在grpc/server.go 的grpc.Server.Serve()方法中已经特别说明了这个事情(而且仅就此问题做了说明):