JasonWang's Blog

为什么iperf测试时UDP会出现高丢包率

字数统计: 1.3k阅读时长: 5 min
2023/01/10

这两天质量的同学反馈说iperf测试时结果很差,跟实际的千兆带宽差别很大。确认了半天,发现内核的各项参数都已经完全按照千兆的目标速率进行配置了,那为什么还是会出现TCP/UDP带宽不足的问题? 记得当时优化参数时,自己摸底测试的TCP结果挺好的,都达到了预期的900Mbps以上,看起来最近有什么修改导致了这个测试结果差异。

偶然的一个机会查看内核配置时,发现最近有人打开了trace功能,看起来很可能是这个修改导致了网络性能的下降了。拿早前未开启trace功能的版本一对比,果真是trace功能影响了TCP的带宽。但是测试UDP还是会出现如下结果,看起來好像网络很差(注意对UDP测试需要通过设置-b参数来限制可能的带宽,否则也可能出现测试结果偏差):

  • 使用iperf默认的的包大小测试(看源码,对UDP来说,默认的包大小为1024, 最大为65507)
1
2
3
4
5
6
7
8

服务端: iperf3 -s -p 8989 -f m
客户端: iperf3 -c 172.20.2.40 -p 8989 -f m -t 30 -u -b 1G

[ 5] 0.00-30.00 sec 710 MBytes 198 Mbits/sec 0.000 ms 0/509813 (0%) sender
[ 5] 0.00-30.19 sec 701 MBytes 195 Mbits/sec 0.201 ms 6626/509809 (1.3%) receiver


由于UDP没有流控,整体的丢包率1.3%还不错,但带宽明显太小了,只有理论值的1/5不到。从这个结果可以看到,实际带宽不足是因为发送端的速率太小了,导致整个通道未被充分占满。这就好比一个粗大的水管,但实际传输的水流太小了,容量利用率不够。要想提高利用率,只能想法提升发送端的速率。iperf中,我们可以通过提高包大小来达到这一目的

  • 使用最大的UDP包大小(65507)进行测试
1
2
3
4
5
6
7
8
9

服务端: iperf3 -s -p 8989 -f m
客户端: iperf3 -c 172.20.2.40 -p 8989 -f m -t 30 -u -b 1G -l 65507


[ ID] Interval Transfer Bitrate Jitter Lost/Total Datagrams
[ 5] 0.00-10.00 sec 1.16 GBytes 1000 Mbits/sec 0.000 ms 0/19079 (0%) sender
[ 5] 0.00-10.18 sec 723 MBytes 595 Mbits/sec 0.282 ms 7508/19079 (39%) receiver

这次测试带宽明显有所提升,但接收端的丢包率却达到了惊人的39%。为什么会出现如此高的丢包率了?这还是要从UDP的传输机制说起了。我们都知道,UDP是无连接的数据报文传输协议,也没有类似TCP滑动窗口的流量控制机制,因此快速的一方很有可能会淹没慢速的一方。这个时候就需要适当的调整慢速一端的socket缓冲区大小了。

对于UDP来说,主要有如下几个参数会影响实际传输时socket缓冲区的大小(可以参考内核文档ip-sysctl.txt):

  • net.core.wmem_default/net.core.wmem_max: 默认、最大的发送缓冲区大小(bytes),如果没用通过setsockopt來设置SO_SNDBUF的值,则会使用内核默认的缓冲区大小
  • net.core.rmem_default/net.core.rmem_max: 默认、最大的接收缓冲区大小(bytes), 类似的,如果没有通过SO_RCVBUF来设置发送缓冲区的值,则使用内核默认的net.core.rmem_default
  • net.ipv4.udp_mem="min pressure max": 系统中所有UDP连接socket可以使用的最小、压力、最大页数(页大小一般为4K),默认值一般在系统启动的时候根据当前可用内存计算出来的
  • net.ipv4.udp_rmem_min/net.ipv4.udp_wmen_min: 系统中单个UDP连接socket可用的最小内存(bytes), 默认是4K

要想减少测试中的丢包率,就需要提高慢速端(也就是接收端)的缓冲区大小,确保其有足够的空间来保存接收到的数据,不至于来不及处理而被内核丢弃。我们可以选择在发送端或者接收端设置缓冲区的大小,对于iperf只能通过-w控制客户端的缓冲区大小, 这里我们直接在客户端设置发送缓冲区的大小为10M

1
2
3
4
5
6
7
8
9

服务端: iperf3 -s -p 8989 -f m
客户端: iperf3 -c 172.20.2.40 -p 8989 -f m -t 30 -u -b 1G -l 65507 -w 10M


[ ID] Interval Transfer Bitrate Jitter Lost/Total Datagrams
[ 5] 0.00-10.00 sec 1.16 GBytes 1000 Mbits/sec 0.000 ms 0/19081 (0%) sender
[ 5] 0.00-10.19 sec 1.16 GBytes 981 Mbits/sec 0.593 ms 0/19079 (0%) receiver

可以看到,丢包率速率下降了到预期的程度。如果我们要在服务端设置接收缓冲区的大小,可以有两种方式: 一种是通过设置net.core.rmem_default大小,一种是修改iperf3的源码,确保服务端也可以通过-w来设置缓冲区的大小。

总结

网络的带宽优化涉及了Linux内核协议栈和网卡驱动,充分理解网络数据的传输流程以及TCP/UDP等传输协议的机制,才有可能找到性能的瓶颈。总的来说,这些优化很值得很深入研究,可以让人完整的把各个知识点都梳理串联起来。

CATALOG
  1. 1. 总结