收发包调优策略(一)

客户需要用到一种场景:A-B-C三台虚拟机位于三个独立的host上,A到B配置vxlan,B到C配置vxlan,A到C不配置vxlan,从而A和B可以通信,B和C可以通信,但是A和C不能直接通信,然后在A上添加路由route add -host IP_of_C gw IP_of_B,同理在C上配置路由route add -host IP_of_A gw IP_of_B,也就是当A打算与C通信时将报文全部转到B,然后在B上配置ip_forward,sysctl -w net.ipv4.ip_forward=1,也就是B只做转发用,A到C的报文会因为默认路由走到B,然后B会修改源mac地址从而转发到C,C向A发送类似。

A打向C的流经过网卡RSS,会均匀的分散到不同的队列上,但是内核中对于从某个队列收到的报文需要再次进行hash决定其由哪个队列发出去,这个时候假设从0号队列收到包然后从1号队列转发出去,就会有切换开销,而且,不同队列收到的包如果转发出去时hash到同一队列,也会产生竞争,这对于转发性能影响非常大。我们现在希望B虚拟机从几号队列收到包就从几号队列发出去,避免切换和竞争开销。这个时候就需要用到xps。

xps:xmit packet steering,也就是发包转向。也就是建立发包队列和cpu的绑定关系,可以是1对1或者1对多。假设我们建立1对1的绑定关系,则在发包的时候就可以根据当前的cpu直接确定发包队列,就不需要hash操作,而且可以避免竞争。所以我们可以在B虚拟机中配置xps,具体方法就是将要绑定的CPU掩码写入xps_cpus:
echo 00000001 > /sys/class/net/eth0/queues/tx-0/xps_cpus
如上是说将eth0的0号队列与0号cpu进行绑定,这样所有由0号CPU处理的收包其发包由0号队列发出。

我们可以用netperf打流,打流的时候设置CPU亲和性为0号cpu,看最终出虚拟机的队列号是否为0来进行验证xps是否起作用。
但是对于我们上面A->B->C的这种转发模型,在B上只设置XPS是不够的,因为内核默认开启RPS和XPS,redhat7.4中RPS默认掩码为0xff,也就是说不管几号队列收上来的报文,内核都会将其重新调度到0-7号cpu进行处理。这个时候虽然我们配置了32个队列,而且由于网卡RSS,虚拟机收包均匀的分散在32个队列上,但是其处理cpu始终是0-7,所以配置的xps后,发包队列就会选择0-7号CPU所对应的队列。从而导致虽然收包分散在32个队列上,但是发包还是集中在7个队列上,产生队列切换和竞争开销,导致性能上不去。
所以我们要将RPS关掉,方法就是将所有队列的rps_cpus设置为0,因为0表是不对应任何cpu,从而保证内核对收包队列的包处理不再做重新调度。这时候我们只要对每个队列中断进行绑核操作就可以强制指定每个队列收上来的包有哪个cpu进行处理,再配合xps,我们就能指定由某个队列手上来的包由特定队列发出去,这样灵活的配置。避免竞争和切换开销,大大提高转发能力。

所以最终方案是:中断绑定+xps来完成消除竞争和切换开销从而提高转发性能。

绑中断的相关资料:

Linux kernel 2.6.21开始支持多队列特性,当网卡驱动加载时,通过获取的网卡型号,得到网卡的硬件queue的数量,并结合CPU核的数量,最终通过Sum=Min(网卡queue,CPU core)得出所要申请中断号的个数,分配给激活每个队列。

当某个queue收到报文时,触发相应的中断,收到中断的核负责该包的处理,我们可以通过设置队列中断的CPU亲和性来将某个队列的中断处理与某个特定的CPU进行一一绑定:
echo 000001 > /proc/irq/irq_num/smp_affinity_list
如上指将CPU0与irq_num进行绑定。

我们可以通过cat /proc/interrupt来查看队列对应的中断号,virtio0-input表示队列0的收包中断,virtio0-output表示队列0的发包中断。

本文遵从CC3.0协议转载请注明:转自凌风技术站

本文标题:收发包调优策略(一)

本文链接地址:http://www.iaccepted.net/network/167.html

相关文章