症状描述:
图1
图2
图3
排查思路:
netstat 获取的发送队列数据来源于对应socket建立时内核结构体struct sock的成员sk_wmem_queued,导致netstat中发送队列数据值高的原因有如下几个可能:
1、网络传输质量差,丢包情况严重,从而导致大量数据包不能及时清理需要重传。
从系统自身统计和抓包的情况来看无丢包情况,故可暂时排除,但不排除在高TPS时网络设备不稳定。
2、带宽原因,按一笔报文500字节,TPS=1000计算,带宽也就500-600k,未达到2M,理论上不会,但有可能造成此症状。
3、报文虽然已通过网卡发送出去但因为没有及时收到对方返回的ACK响应故仍保留在发送队列(流动窗口)中。目前系统默认的响应ACK间隔为200毫秒(通过no –o fasttimo命令可见),对CUPS这种单工线路因为银联端的响应报文是走另一条线路返回,所以ACK应答无法跟包快速返回,只能在达到200毫秒或两个MSS后才应答,故在高TPS时会在一定程度上造成我方send-q值高。
对这种可能仅需关闭服务端的ack延时响应再观察高tps时客户机上对应socket的发送队列即可。目前在测试环境测试情况来看当将接收端的ack应答设为实时应答时,发送端的发送队列值基本保持为0(见测试案例二:测试报文大小168字节,TPS=2000)。
4、报文因两端的发送和接收空间设置不一致导致
5、报文因发送策略或网卡设置原因未实时发送出去。具体依据网卡是否支持offload特性(即TCP分段工作是由系统内核完成还是网卡完成)可分两类情况来分析。
l 由系统内核进行TCP分段后再发至网卡。应用程序调用系统send函数通过Nagle、Cork、NoDelay等策略将数据组包发至网卡,网卡通过中断机制尽可能以接近MTU的大小将数据发送出去。当TPS很高时因MTU较小(几笔报文即能达到MTU)故不大会导致netstat发送队列的值太高。且此时tcpdump抓取的包大小不会超过MTU的大小(一般是1500字节)
l TCP分段工作由网卡完成。内核收到应用程序发送的数据后会通过延迟数据包的发送,来减少TSO分段的次数,达到减小CPU负载的目的。此时tcpdump抓取的包大小可能超过MTU的大小。
由症状描述中生产抓包情况来看(包大小超过MTU),生产环境的网卡肯定是支持并开启了TSO功能(也可通过entstat -d en0命令确认)。故对第二种可能仅需验证关闭TSO功能后netstat值是否仍会很高即可。
测试验证:
验证环境:
客户机 144.131.254.153/144.131.254.164
服务端 144.131.254.154:30011
考虑到去CUPS线路为单工双链模式,在两机间建立单工链路,从客户机向服务端以TPS=2000的频率发送长168字节的报文。
测试案例一:
相关设置
服务端 | 客户端 |
tcp_nodelayack=0 fasttimo=200 tcp_sendspace=131072 tcp_recvspace=65536 TSO功能开启 | tcp_nodelay=0 fasttimo=200 tcp_sendspace=131072 tcp_recvspace=65536 TSO功能开启 |
对应的netstat执行结果
未出现生产上的send-q达到上万的情况,多数时候发送队列值在2-3千字节。
测试案例二:
相关设置
服务端 | 客户端 |
tcp_nodelayack=1 fasttimo=200 tcp_sendspace=131072 tcp_recvspace=65536 TSO功能开启 | tcp_nodelay=0 fasttimo=200 tcp_sendspace=131072 tcp_recvspace=65536 TSO功能开启 |
对应的netstat执行结果