昨天花了大量时间在“调优”:因为服务器的网络输出带宽死活与计算值不符合。理论判断网络输出带宽应该是90Mbps,但是检测却只有50+Mbps而已。做了几个试验后,我们觉得是服务器性能问题,于是祭出profile杀器,可是优化了几个耗时多的函数后,带宽巍然不动。之后我们先xxoo,再 ooxx,搞得是鸡飞狗跳,最后发现一方面是由于我们被带宽显示工具误导了,另一方面当udp包较小的时候,并不是所有网络带宽都可使用。
1)我们在Linux主机用“iftop -i eth0”查看网络带宽,iftop显示的情况极其详尽,但是它会影响可用带宽!!!当我们关掉iftop进程后,主机的输出带宽立马从50+Mbps上升到80Mbps。所以iftop适合在发现带宽与理论不一致的时候用来查看是否有其他连接在使用带宽。平时显示带宽用“watch -n 1 "vnstat -tr 2"”。 windows下直接用任务管理器,查看“联网”选项卡即可。
2)当udp包较小的时候,没办法充分使用所有带宽。下表两台主机都使用100M网卡接入100M局域网。表中第一行表示使用Linux主机发送,Windows主机接收;第二行表示使用Windows发送,Linux主机接收。带宽并不是确定不变的,表中的数值只是近似值。左边表示发送方的带宽统计,右边表示接收方的带宽统计,如果基本一致则只列出一项。带宽单位均是bps。
udp包长度(不含udp头)
5B
10B
20B
40B
80B
160B
320B
640B
1280B
Linux发送
47M/60M
51.2/60M
62M
73.5M
80M
86M
91M
95M
97M
Windows发送
41M/40M
50/43M
70M/54M
76M/62M 80M/71M
86M/80M
92M/87M
96M/91M 97M/93M
发送带宽和接收带宽不一致主要有几个原因:带宽统计工具不是十分精确;较小的包会填充到最小长度(46-8-20=18);还有就是局域网内也是会丢包的。下表列出了每秒发送/接收的包的数目。不过我已经得到我想知道的东西了,所以只是随便测试几项哈哈:)
udp包长度(不含udp头)
10B
40B
160B
640B
Linux发送
126657/125695
114086/113607
54128/53686
17560/17437
Windows发送
114824/114636
116841/116388
55235/55191
17542/17525
收发包率的差别要比带宽来得小。这也说明了我们使用的带宽统计工具不是十分精确。(收发包的数目在程序中统计,是准确的)
3) 当目标主机是windows时,如果没有进程接收udp数据,对数据发送是有影响的。因为windows会对每个udp包响应一个“端口不可达”的 ICMP包。这个包在我机器上是90字节(720bits)。比如udp size=320时,Linux=>Windows:如果windows有进程接收的话,windows入口带宽大概是91M,出口为0;如果 windows没有进程接收,入口带宽则只有50多M,出口带宽则有30多M。
===================华丽的分割线=====================
结论:如果要充分利用带宽资源,udp包的平均长度不能太小。在测试环境下,160B字节的udp包大概可以利用86%的理论带宽,640B则可以利用到93%+。当然,这只是在两台主机上的测试结论。如果网卡或者机器更牛x,估计还是有上升空间的。
===================2010-12-27=====================
今天再次运行该程序,发现测试小包时的结果有误:那个瓶颈是CPU造成的,而不是网卡IO造成的。在多核机器上通过多开进程的方式可以提高小包时的可用带宽。但如果单进程时CPU使用率本就不满的时候,提高进程数是没有用的。比如通过多开进程,linux发送10B可以达到58Mbps而不是上表中的51.2Mbps,udp包长大于30时,多开进程不起效果。至于windows,由于现在硬件很强,单进程直接就可以到58Mbps了,cpu未满,提高进程数也不起效果。最新的测试结果(40B以上没有变化,不列出来,windows和linux差别不大,故只列一行)
udp包长度(不含udp头)
5B
10B
20B
52.8M
58.42M
68.1M