TCP的SYN队列和Accept队列( 二 )

还可以通过我们的SystemTap脚本来观察这个数据: resq.stp
假如程序调用accept()不够快?

TCP的SYN队列和Accept队列

文章插图
 
如果程序调用accept()不够快会发生什么呢?
TcpExtListenOverflows / LINUX_MIB_LISTENOVERFLOWSTcpExtListenDrops / LINUX_MIB_LISTENDROPS发生这种情况时 , 我们只能寄希望于程序的处理性能稍后能恢复正常 , 客户端重新发送被服务端丢弃的包 。
内核的这种表现对于大部分服务来说是可接受的 。顺便一提 , 可以通过调整 net.ipv4.tcp_abort_on_overflow 这个全局参数来修改这种表现 , 但是最好还是不要改这个参数 。
可以通过查看nstat的计数来观察Accept队列溢出的状态:
$ nstat -az TcpExtListenDropsTcpExtListenDrops 49199 0.0但是这是一个全局的计数 。观察起来不够直观 , 比如有时我们观察到它在增长 , 但是所有的服务程序看起来都是正常的 。此时我们可以使用ss命令来观察单个监听端口的Accept队列大小:
$ ss -plnt sport = :6443|catState Recv-Q Send-Q Local Address:Port Peer Address:PortLISTEN 0 1024 *:6443 *:*Recv-Q 这一列显示的是处于Accept队列中的socket数量 ,  Send-Q 显示的是队列的最大大小 。在上面的例子中 , 我们发现并没有未被程序accept()的socket , 但是我们依然发现ListenDrops计数在增长 。
这是因为我们的程序只是周期性的短暂卡住不处理新的连接 , 而非永久性的不处理 , 过段时间程序又恢复了正常 。这种情况下 , 用ss命令比较难观察这种现象 , 因此我们写了一个 SystemTap脚本  , 它会hook进内核 , 把被丢弃的SYN包打印出来:
$ sudo stap -v acceptq.stptime (us) acceptq qmax local addr remote_addr1495634198449075 1025 1024 0.0.0.0:6443 10.0.1.92:285851495634198449253 1025 1024 0.0.0.0:6443 10.0.1.92:505001495634198450062 1025 1024 0.0.0.0:6443 10.0.1.92:65434...通过上面的操作 , 可以观察到哪些SYN包被ListenDrops影响了 。从而我们也就可以知道哪些程序在丢失连接 。




推荐阅读