如今的高性能服务器上运行着更多的处理器,运行在其上的虚拟机拥有的vCPU数量也越来越多。传统的单virtio-net队列中,由于网络性能无法随着vCPU的数量动态的伸缩,导致客户机的协议栈规模受限,单一的收发队列也使得虚拟机无法并行传输数据报文,网络性能受限。openstack对网卡多队列的支持应运而生。
openstack环境下的网卡多队列使用
openstack在默认设置中并未启动image的多队列属性。需要通过如下命令修改image属性。
glance image-update --property hw_vif_multiqueue_enabled=**true** ${IMAGE_ID}
libvirt API driver |
---|
hw_vif_multiqueue_enabled |
If true, this enables the virtio-netmultiqueue feature. In this case, the driver sets the number of queues equal to the number of guest vCPUs. This makes the network performance scale across a number of vCPUs. |
true / false |
这里需要注意的是对镜像属性的修改并不会影响到已经使用该镜像创建的虚拟机。用户需要重建原有使用该镜像的虚拟机或者新建使用该镜像的虚拟机,对应属性才会生效。
如果用户需要修改已经处于运行状态的虚拟机,可以通过virsh edit 虚拟机的xml文件实现虚拟机支持网卡多队列。
docker **exec** -it -uroot nova_libvirt bash
virsh list
virsh edit instance-xxx
###这里将队列数修改为8
virtsh shutdown instance-xxx
virtsh start instance-xxx
理论上修改后该镜像启动的虚拟机队列长度固定为虚拟机的核数。但针对宿主机内核版本的不同,实际虚拟机的可用队列存在上限(3.X为8个,4.X为256个)。在实际应用中虚拟机的网卡多队列也是会消耗宿主物理机的CPU性能的。尤其当CPU超配严重时,开启网卡多队列并不一定是个好的选择。
/*3.X内核代码*/
#define DEFAULT_MAX_NUM_RSS_QUEUES (8)
/* DEFAULT_MAX_NUM_RSS_QUEUES were choosed to let the rx/tx queues allocated for
* the netdevice to be fit in one page. So we can make sure the success of
* memory allocation. TODO: increase the limit. */
#define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES
/*4.X内核代码*/
/* MAX_TAP_QUEUES 256 is chosen to allow rx/tx queues to be equal
* to max number of VCPUs in guest. */
#define MAX_TAP_QUEUES 256
网卡多队列设置
网卡多队列需要硬件和驱动同时支持。上一章节阐述了openstack控制层及虚拟化层对网卡多队列的相应支持,本节将从虚拟机内部观察多队列网卡的相应设置信息。
查看网卡pci设备
yum install pciutils –y
lspci
lspci -vvvs 00:03.0
MSI-X Capability中断机制与MSI Capability的中断机制类似。PCIe总线引出MSI-X机制的主要目的是为了扩展PCIe设备使用中断向量的个数,同时解决MSI中断机制要求使用中断向量号连续所带来的问题。当出现MSI-X:Enable,可以判断该网卡支持网卡多队列。
查看修改网卡多队列信息
查看网卡的多队列信息,图示显示当前使用队列数为1,最大可用队列数为4。
ethtool -l eth0
修改当前网卡使用队列数。
ethtool –L eth0 combined 4
中断平衡
每个网卡队列对应的中断默认并没有跟相应的CPU做绑定,也就是说默认情况下这些中断都是没有绑定的,那么按内核默认的处理策略,对于没有绑定的中断,默认都会在CPU0上运行,这样会导致CPU占用不均衡。过多的网卡收包和发包中断集中在一个CPU上,在系统繁忙时,CPU对网卡的中断无法响应,这样导致了服务器端的网络性能降低。解决这种不均衡通常使用人为绑定中断和启动irqblance。
人为绑定网卡队列中断
通过下述命令查看网卡队列中断,从截图可以分析出网卡的4个队列Tx/Rx分别占据了25-32这8个中断向量号。
cat /proc/interrupts
通过下述命令可以查看具体某个中断的CPU亲和性。图示显示中断34绑定在CPU2上。(hex04 = bin100,按位分别对应CPU0,CPU1,CPU2)
Smp_affinity与Smp_affinity_list 显示的是同一项信息。不过前者以十六进制显示,后者以十进制显示
#该命令查看中断34的CPU绑定关系
cat /proc/irq/34/smp_affinity
cat /proc/irq/34/smp_affinity_list
通过下述命令可以修改某个中断与CPU的绑定关系。
#该命令将中断34与CPU1绑定
echo 2 > /proc/irq/34/smp_affinity
irqbalance
irqbalance是一个开源项目(https://github.com/Irqbalance/irqbalance)。在该项目主页上描述道:Irqbalance is a daemon to help balance the cpu load generated by interrupts across all of a systems cpus.
irqbalance的基本原理很简单:就是周期计算各个CPU上的中断数量,发现不均衡时,动态通过/proc接口设置指定中断的CPU亲和性,进行绑定。当只有一个中断时,无论将这个中断绑定到哪个CPU,都会不均衡。irqbalance进行均衡的粒度为不同的中断,当系统中有很多不同类型的中断,基本有用,但在上述的情况下,只有一个中断(或者少量中断),此时irqbalance无能为力。当系统处于 Power-save mode时,irqbalance 会将中断集中分配给第一个 CPU,以保证其它空闲 CPU 的睡眠时间,降低能耗。
irqbalance根据系统中断负载的情况,自动迁移中断保持中断的平衡,同时会考虑到省电因素等等。 但是在实时系统中会导致中断自动漂移,对性能造成不稳定因素,在高性能的场合建议关闭。
查看irqbalance状态
systemctl status irqbalance.service
停止
systemctl stop irqbalance.service
RPS/RFS
目前服务器的CPU越来越强劲,CORE数量也达到了数十乃至上百的级别。而实际物理网卡的队列数量往往与庞大的CPU核心数量不能匹配。当网卡硬件队列数量远小于CPU核心数量时,即便设定了网卡的中断亲和,实际在处理网卡中断请求时,软硬中断依旧局限在少量的CPU核心之上。此时就可以通过RPS/RFS这两个特性进一步分散网卡中断请求。
RPS(Receive Packet Steering)
RPS特性把收到的报文依据一定的hash规则(根据IP四元组SIP,SPORT,DIP,DPORT)给hash到不同的CPU上去,以达到各个CPU负载均衡的目的。 这里只是把软中断做负载均衡,不去改变硬中断。因而对网卡没有任何要求。实际该功能也适用于单队列网卡多核CPU的环境。
RPS本身并不能减少CPU的软中断次数,而是将软中断从执行硬中断的CPU核心上分离至其他空闲CPU核心,减少单一CPU核心的中断次数,降低软中断执行时间。
Linux通过配置文件的方式指定哪些cpu核参与到报文的分发处理,配置文件存放的路径是:/sys/class/net/(dev)/queues/rx-(n)/rps_cpus。下属命令设置核0,2,4,6参与对rx-0的分发处理。
echo 55 > /sys/**class**/net/eth0/queues/rx-0/rps_cpus
RFS(Receive Flow Steering)
RPS将数据包软中断均衡至不同CPU,若处理数据包的应用程序所在CPU与软中断处理报文的CPU不一致,将大大降低CPU cache效率。这里就需要通过RFS特性进行弥补。RFS需要依赖于RPS,它跟RPS不同的是不再简单的依据网络报文来做hash,而是根据flow的特性,即application在哪个核上来运行去做hash,从而使得有更好的数据局部性。所以RFS相比于RPS,主要差别就是在选取分发处理报文的目标CPU上,而RFS还需要依靠RPS提供的机制进行报文的后续处理。
Linux下RFS是默认关闭的。开启RFS需要修改下面两个文件。在一个8核环境下,rps_flow_cnt设置为4096,则rps_sock_flow_entries设置为4096*8。对于内存充裕的环境可以适当调大相应参数设置。
echo 32768 **>** /proc/sys/net/core/rps_sock_flow_entries
echo 4096 **>** /sys/class/net/device/queues/rx-0/rps_flow_cnt
参考链接
http://aspirer.wang/?p=820
http://laoar.github.io/blog/2017/05/07/rps/
https://www.slideshare.net/gokzy/rpsrfs
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/performance_tuning_guide/network-rfs
https://tqr.ink/2017/07/09/implementation-of-rps-and-rfs/