本文目录
CPU亲和性,指的是将进程绑定在某个核上运行,让操作系统不会将进程动态的迁移到其它核去运行。
iperf3在某些支持CPU亲和性设置的操作系统中(比如Linux)可以指定iperf3运行在某个绑定的CPU核里。
1、man iperf3查看到的官方说明如下:
-A, --affinity n/n,m
Set the CPU affinity, if possible (Linux, FreeBSD, and Windows only). On both the client and server you can set the local affinity by using the n form of this argument (where n is a CPU number). In addition, on the client side you can override the server’s affinity for just that one test, using the n,m form of argument. Note that when using this feature, a process will only be bound to a single CPU (as opposed to a set containing potentially multiple CPUs).
2、翻译一下:
可以使用-A或者–affinity参数,后面跟上CPU编号(如果你不知道怎么查看主机的CPU情况,可参见如何知道当前主机有几个CPU有哪些CPU)。
设置CPU亲和性,如果操作系统支持(比如Linux,FreeBSD和windows)。使用n格式,可以在服务端和客户端设置本地CPU亲和性(n代表cpu的编号)。使用n,m格式,可以在客户端设置客户端自己的亲和性(n表示客户端跑在客户端主机的第n个核)以本次测试过程中服务端的亲和性(n表示服务端本次测试跑在服务端主机的第m个核)。注意,当你使用了这个参数后,iperf3进程就只要跑在指定的CPU核上(作为对比,如果不设置的话,iperf3可以跑在操作系统指定的多个CPU核集合里,通常是主机的所有CPU核)
3、使用n格式来设置CPU亲和性
n格式设置指定的是客户端或者服务端自己的CPU的亲和性设置。我们使用如下命令将客户端和服务端分别指定在第2号CPU和第2号CPU,然后启动1Gbps的带宽测试。注意为了让测试结果更加明显,我们的客户端用的是8核i8的x86机器,单核主频为4.0Ghz,而服务端使用的是树莓派4B,单核主频为1G的ARM A53 CPU。
3.1、服务端
用以下命令,启动服务端,将iperf3服务端进程绑定在cpu2上,客户端开始打UDP流后,我们看到top显示的CPU 负荷如下所示,cpu2的 CPU占用率已经达到100%,其它几个核的占用率还是很低的(CPU0稍微有些占用,是因为LINUX的TCP/IP协议栈运行在CPU0上),说明iperf3进程成功绑定在cpu2上。
iperf3 -s -A 2
3.2、客户端
用以下命令,绑定第2号CPU进行发送数据,发送速率为750Mbps.
/usr/bin/iperf3 -c 192.168.3.60 -u -b 750M -t 100 -A 2
我们可以看到cpu2的CPU占用率明显比其它几个核要高。说明iperf3运行在CPU上,当我们把上面的-A 2换成-A 6的时候,我们可以看到cpu6的CPU占用率明显比其它几个核。说明-A生效了。
3.3、测试结果
在带宽测试过程中,我们通过top命令可以看到,客户端的第2号CPU的使用率明显上升,其它CPU核的使用率没有什么变化,而服务端的第2号CPU的使用率明显上升,其它CPU核的使用率没有什么变化。说明不管是在客户端还是服务端iperf3进程成功绑定在了指定的CPU上。
4、使用n,m格式来设置CPU亲和性
这个格式只能在客户端使用,但会在客户端和服务端同时生效,且只是在本次测试过程中生效,客户端用m指定的服务端亲和性在本次测试中会覆盖原先服务端启动时通过n格式指定的亲和性设置。本次测试完成后iperf3客户端自动退出。本次测试完成后服务端会重新开始监听指定端口(默认5102)开始下一次测试过程,这时候服务端会恢复回服务端启动时在服务端通过n格式指定的cpu亲合性。
我们使用如下命令将服务端分别指定在第2号CPU,再通过客户端命令将客户端指定在第1号CPU(n=1)服务端指定在3号CPU(m = 3),然后启动1Gbps的带宽测试。注意我们的客户端用的是4核i3的x86机器,单核主频为3.6G,而服务端使用的是树莓派4B,单核主频为1G的ARM A53 CPU。
4.1、服务端运行命令
运行以下命令,将服务端绑定到第2号CPU上。
iperf3 -s -A 2
4.1、客户端运行命令
运行以下命令,将客户端指定在第1号CPU(n=1)服务端指定在3号CPU(m = 3)。
/usr/bin/iperf3 -c 192.168.3.60 -u -b 750M -t 100 -A 1,3
4.2、测试结果
在带宽测试过程中,我们通过top命令可以看到,而服务端的第3号CPU的使用率明显上升,其它CPU核的使用率没有什么变化。说明在本次测试过程中服务端的iperf3按客户端命令的指示从原来的指定的第2号CPU切换到了第3号CPU上。
5、iperf3 CPU亲和性配置的推荐方案
不设置亲和性的情况下,Linux会自行根据当前各个CPU核的负荷情况,将iperf3调度到linux系统认为比较合适的CPU核中去运行。这样会带来的问题有二个:
- iperf3默认会先跑在第0个CPU上,那么因为TCP/IP协议栈本身的处理是固定在第0号CPU的,会在刚刚开始测试时,第0号CPU很快负荷变得很高而出现来不及处理导致的丢包
- Linux发现第0号CPU太忙,将iperf3进程调度到其它CPU的过程中,出现短暂的收包暂停而引起这段时间内的丢包发生
如下图,未指定服务端运行于哪个CPU时,我们可以看到上述的二个问题的存在(丢包率在某些时间上升,此时我们如果对应的看TOP的话,就会发现发生丢包时,有很多都是发生CPU切换了)。
所以推荐在CPU能力受限的系统(即CPU处理能力不够而导致无法将网络吞吐量打到最高值的系统)上,一开始就指定好CPU的亲和性,一般来说LINUX的TCP/IP的协议栈是固定在第某一个CPU核处理的,且只使用一个CPU核来处理一个网卡的收发包中断,处理TCP/IP本身会占用不少的CPU处理能力,所以一般来说我们要避开这些CPU。可以通过查看网卡中断在哪个CPU核处理中描述的方法来查看网卡的中断由哪个CPU核处理。
那么服务端和客户端可以分别使用如下的推荐设置(如果你的系统中,你知道哪个CPU最空闲,你可以将亲和性指定到最空闲的CPU则可),让客户端和服务端分别跑在各自主机的第2号CPU核和第3号CPU核。
iperf3 -s -A 2
iperf3 -c 192.168.3.1 -u -b 1000m -A 3
6、NUMA 架构下的CPU亲和性设置
如果你的lscpu显示的NUMA节点数量大于1,那么最好还要避免使用跨NUMA的CPU核,即让IPERF跑在和网卡/TCPIP协议栈同一个NUMA节点下的不同CPU。