ovs+dpdk numa感知特性验证
0.介绍
本测试是为了验证这篇文章中提到的DPDK的NUMA感知特性。
简单来说,在ovs+dpdk+qemu的环境中,一个虚拟机牵涉到的内存共有三部分:
- DPDK为vHost User设备分配的Device tracking memory
- OVS为网络通信分配的mbufs
- QEMU为虚拟机分配的内存
未开启DPDK的NUMA感知特性时,所有Device tracking memory都会使用同一个NUMA节点中的内存,如果这时QEMU为两台虚拟机分配的内存刚好在两个不同的NUMA节点上,那么机器间的网络通信效率就会有损耗。
开启了DPDK的NUMA感知特性后,在QEMU创建虚拟机后,DPDK会将vHost User设备的Device tracking memory挪到与虚拟机相同的NUMA节点上,并且DPDK还会通知OVS,以让OVS把与该虚拟机相关的mbufs分配在与虚拟机相同的NUMA节点上。
理论上这应该能增加两虚拟机的网络通信效率,所以本文就来用实验探究一下
但在实验之前,我对结果的预期是悲观的,我感觉(感性的)虚拟机间的通信效率更多的受制于虚拟机本身的配置,尤其是在虚拟机的规格比较差的情况下。
本文将进行对照测试,分别在“带NUMA感知的DPDK环境”与“不带NUMA感知的DPDK环境”进行测试,每次测试都在两个不同的NUMA节点上分别启动一台配置相同的虚拟机,使用netperf对两虚拟机间的网络通信效率进行测量。
虚拟机配置: 2*vcpu, 4G RAM, CentOS 7
1.测试环境配置
host的基本配置如下:
项 | 版本/配置 |
---|---|
CPU | 2 * [Intel(R) Xeon(R) CPU E5-2698 v3 @ 2.30GHz] |
OVS | ovs-vsctl (Open vSwitch) 2.7.0 |
DPDK | stable-16.11.1 |
[root@compute2 zsb]# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62
node 0 size: 130975 MB
node 0 free: 102930 MB
node 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 61 63
node 1 size: 131072 MB
node 1 free: 114196 MB
node distances:
node 0 1
0: 10 21
1: 21 10
1.1.numa库与命令行软件的安装
yum install numactl
yum install numactl-libs
yum install numactl-devel
1.2.内核启动参数配置
16个1G规格的大页,逻辑核心1-17,33-49不参与内核处理器调度
hugepagesz=1G
hugepages=16
iommu=pt
intel_iommu=on
isolcpus=1-17,33-49
1.3.hugepage挂载设置
移除原有的2M规格大页的挂载点,只挂载规格为1G的大页
umount /dev/hugepages
mkdir /mnt/huge_1GB
mount -t hugetlbfs -o pagesize=1G none /mnt/huge_1GB
1.4.dpdk的编译
打开numa感知的编译选项
CONFIG_RTE_LIBRTE_VHOST_NUMA=y
编译
export DPDK_DIR=<DPDK_DIR>
export DPDK_TARGET=x86_64-native-linuxapp-gcc
export DPDK_BUILD=$DPDK_DIR/$DPDK_TARGET
make install T=$DPDK_TARGET DESTDIR=install
1.5.ovs的编译安装
export OVS_DIR=<OVS_DIR>
cd $OVS_DIR
./configure --with-dpdk=$DPDK_BUILD CFLAGS="-Ofast -g"
make CFLAGS="-Ofast -g"
make install
1.6.ovs的启动与pmd轮询核心亲和性的配置
pmd-mask被设置为0x0c0000000c,即pmd亲和2 3 34 35四个逻辑核心。其中2与34是同一个物理封装里同一个core的两个超线程,位于NUMA 0,3与35是另外一个物理封装里的同一个core的两个超线程,位于NUMA 1。如下表
逻辑核心编号 | 物理封装编号 | core编号 | 属于的NUMA节点 |
---|---|---|---|
2 | 0 | 1 | 0 |
34 | 0 | 1 | 0 |
3 | 1 | 1 | 1 |
35 | 1 | 1 | 1 |
rm -rf /usr/local/etc/openvswitch/conf.db
mkdir -p /usr/local/etc/openvswitch
ovsdb-tool create /usr/local/etc/openvswitch/conf.db $OVS_DIR/vswitchd/vswitch.ovsschema
mkdir -p /usr/local/var/run/openvswitch
ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \
--remote=db:Open_vSwitch,Open_vSwitch,manager_options \
--private-key=db:Open_vSwitch,SSL,private_key \
--certificate=db:Open_vSwitch,SSL,certificate \
--bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \
--pidfile --detach --log-file
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true
ovs-vsctl --no-wait set Open_vSwitch . other_config:pmd-cpu-mask=0x0c0000000c
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem="1024,1024"
export DB_SOCK=/usr/local/var/run/openvswitch/db.sock
ovs-vswitchd unix:$DB_SOCK --pidfile --detach --log-file
1.7.创建bridge与port
ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev
ovs-vsctl add-port br0 port1 \
-- set interface port1 type=dpdkvhostuserclient \
-- set interface port1 options:vhost-server-path=/var/lib/openvswitch/port1
ovs-vsctl add-port br0 port2 \
-- set interface port2 type=dpdkvhostuserclient \
-- set interface port2 options:vhost-server-path=/var/lib/openvswitch/port2
1.8.启动虚拟机的配置
启动虚拟机的libvirt domain xml文件如下所示,注意两台虚拟机配置有差异的地方均有注释
注意虚拟机1配置vcpu时,将cpuset设置为6,38,在host上,6号与38号逻辑cpu属于NUMA node 0,而5,37属于NUMA node 1
<domain type='kvm'>
<!-- 另外一台虚拟机:NUMA_Awareness_test_2 -->
<name>NUMA_Awareness_test_1</name>
<memoryBacking>
<hugepages/>
</memoryBacking>
<!-- 另外一台虚拟机:cpuset="5,37" -->
<vcpu placement='static' cpuset="6,38">2</vcpu>
<cpu mode='host-model'>
<model fallback='allow'/>
<topology sockets='2' cores='1' threads='1'/>
<numa>
<cell id='0' cpus='0-1' memory='4194304' unit='KiB' memAccess='shared'/>
</numa>
</cpu>
<resource>
<partition>/machine</partition>
</resource>
<os>
<type arch='x86_64' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='no'/>
</pm>
<devices>
<emulator>/usr/libexec/qemu-kvm</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<!-- 另外一台虚拟机 file='/export/zsb/image/NUMA_Awareness_test_2.qcow2' -->
<source file='/export/zsb/image/NUMA_Awareness_test_1.qcow2'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='pci' index='0' model='pci-root'/>
<controller type='ide' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<controller type='virtio-serial' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</controller>
<interface type='vhostuser'>
<!-- 另外一台虚拟机:path='/var/lib/openvswitch/port2' -->
<source type='unix' mode='server' path='/var/lib/openvswitch/port1'/>
<model type='virtio'/>
<driver name='vhost'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<input type='tablet' bus='usb'>
<address type='usb' bus='0' port='1'/>
</input>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'>
<listen type='address' address='0.0.0.0'/>
</graphics>
<sound model='ich6'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</sound>
<video>
<model type='cirrus' vram='16384' heads='1' primary='yes'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</memballoon>
</devices>
<seclabel type='none' model='none'/>
<seclabel type='dynamic' model='dac' relabel='yes'/>
</domain>
在虚拟机启动后,编辑虚拟机的网络设置脚本,给两个虚拟机分别配上10.0.0.1与10.0.0.2的IP地址
vim /etc/sysconfig/network-scripts/ifcfg-eth0
--------------------------------
DEVICE=eth0
TYPE=Ethernet
BOOTPROTO=none
ONBOOT=yes
PREFIX=24
# 对于另外一台虚拟机,设置IP地址为10.0.0.2
IPADDR=10.0.0.1
为了方便ssh到虚拟机中,我们在host上创建一个namespace,并创建一个veth-pair设备,把veth-pair的一端放在namespace中,另一端接在ovs-bridge上,从该namespace中ssh到两个虚拟机
其中namespace的名为numa_awareness_test
veth-pair设备中,接入ovs-bridge的设备名为veth-ovs,接入namespace的设备名为veth-ns
ip netns add numa_awareness_test
ip link add name veth-ovs type veth peer name veth-ns
ip link set veth-ovs up
ip link set veth-ns netns numa_awareness_test
ip netns exec numa_awareness_test ip link set dev lo up
ip netns exec numa_awareness_test ifconfig veth-ns 10.0.0.3/24 up
ovs-vsctl add-port br0 veth-ovs
为了能登录到虚拟机中,还需要关闭掉namespace中veth-ns的checksum offload功能
ip netns exec numa_awareness_test ethtool -K veth-ns tx off
之后通过在namespace中执行ssh就可登录到虚拟机上
ip netns exec numa_awareness_test ssh 10.0.0.1
ip netns exec numa_awareness_test ssh 10.0.0.2
另外为了方便监控hugepage的使用情况,可以用以下一个简单的bash脚本进行监测
#! /bin/bash
function printRed() {
printf "\e[1;31m$1\e[1;0m"
}
printRed "----------------\n"
printRed "Hugepagesz = 1GB\n"
total=$(cat /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages)
free=$(cat /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/free_hugepages)
printRed " Numa Node 0: Total: $total\n"
printRed " Free: $free\n"
total=$(cat /sys/devices/system/node/node1/hugepages/hugepages-1048576kB/nr_hugepages)
free=$(cat /sys/devices/system/node/node1/hugepages/hugepages-1048576kB/free_hugepages)
printRed " Numa Node 1: Total: $total\n"
printRed " Free: $free\n"
printRed "----------------\n"
printRed "Hugepagesz = 2MB\n"
total=$(cat /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages)
free=$(cat /sys/devices/system/node/node0/hugepages/hugepages-2048kB/free_hugepages)
printRed " Numa Node 0: Total: $total\n"
printRed " Free: $free\n"
total=$(cat /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages)
free=$(cat /sys/devices/system/node/node1/hugepages/hugepages-2048kB/free_hugepages)
printRed " Numa Node 1: Total: $total\n"
printRed " Free: $free\n"
printRed "----------------\n"
2.测试结果
2.1.采用NUMA感知
在两台虚拟机启动成功之后,查看hugepage的使用情况,如下:
[root@compute2 xml]# ../sh/checkHugepages.sh
----------------
Hugepagesz = 1GB
Numa Node 0: Total: 8
Free: 3
Numa Node 1: Total: 8
Free: 3
----------------
Hugepagesz = 2MB
Numa Node 0: Total: 1024
Free: 1024
Numa Node 1: Total: 1024
Free: 1024
----------------
可以看到两个NUMA节点上每个虚拟机占用了4G内存,ovs分别在两个NUMA节点上占用1G内存,与预期相符
另外查看htop命令的输出,可以看到2号逻辑CPU(在htop中显示为3)与35号逻辑CPU(在htop中显示为36)被PMD轮询使用,这是符合预期的,2号逻辑CPU属于NUMA node 0,而35号逻辑CPU属于NUMA node 1。
虽然PMD轮询线程的掩码设置了4个逻辑CPU,但只有两个在工作,这是因为在环境中只有两个vHost User类型的ovs-port存在的原因。
另外,2号和34号其实是同一颗物理核心虚出来的两个超线程,3号与35号也是如此,虽然显示上3号逻辑核心与34号逻辑核心并没有工作,但其实已经在工作的2号核心与35号核心基本能榨干两个物理核心的性能。
而两个虚拟机在运行性能测试工具时,分别导致了逻辑核心5号与6号(在htop中分别显示为6号与7号)高占用,这也是符合预期的,说明两个虚拟机分别运行在两个不同的NUMA节点上。但对应的37号和38号逻辑核心没有什么占用,基本上是因为netperf工具是单线程程序的原因。
总的来说,配置如下图所示:
接下来分别在两台虚拟机上进行测试:
使用netperf工具进行测试
在10.0.0.1上运行服务端,在10.0.0.2上运行客户端,五分钟带宽测试的结果如下:
[root@localhost ~]# netperf -H 10.0.0.1 -t TCP_STREAM -l 300
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.0.0.1 (10.0.0.1) port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 300.00 6063.37
将netperf的客户端与服务端对换,再次进行5分钱带宽测试,结果如下:
[root@localhost ~]# netperf -H 10.0.0.2 -t TCP_STREAM -l 300
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.0.0.2 (10.0.0.2) port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 300.00 5826.15
2.2.不采用NUMA感知
测试配置上与采用NUMA感知配置不同的地方在于
- 关闭dpdk编译时的CONFIG_RTE_LIBRTE_VHOST_NUMA选项,重新编译dpdk与ovs
- 配置及启动ovs的过程中,将PMD轮询线程的掩码设置为0x1400000014,即使用2 4 34 36四颗核心,这四颗核心都属于NUMA node 0,且物理是是为两颗物理核心虚拟出来的四个超线程
- 配置及启动ovs的过程中,将dpdk-socket-mem设置为2048,0,这样ovs+dpdk会占用NUMA node 0上的2G内存自用
- 两台虚拟机的virsh domain xml配置文件不做更改,即虚拟机的配置是完全相同的
在这个场景中,
- ovs+dpdk占用NUMA node 0上的2G hugepage 内存,即ovs的mbufs与dpdk的deivce tracking memory都将分配在NUMA node 0上
- 而两个虚拟机的内存分配和之前一样,即qemu-kvm为虚拟机分配的内存依然分散在两个NUMA节点上
- PMD轮询依然使用了四个逻辑核心,实际上是两个物理核心,与上相同,不同的是这次四个轮回核心将位于同一个NUMA节点上
虚拟机启动后,hugepage的使用情况如下:
[root@compute2 xml]# ../sh/checkHugepages.sh
----------------
Hugepagesz = 1GB
Numa Node 0: Total: 8
Free: 2
Numa Node 1: Total: 8
Free: 4
----------------
Hugepagesz = 2MB
Numa Node 0: Total: 1024
Free: 1024
Numa Node 1: Total: 1024
Free: 1024
----------------
其中Node 0上有2G内存供ovs+dpdk使用,再就是每个Node都有4G内存供虚拟机使用
htop的输出如下所示(运行netperf测试中):
总的来说,配置如下图所示:
接下来依然同上进行测试:
在10.0.0.1上运行服务端,在10.0.0.2上运行客户端,五分钟带宽测试的结果如下:
[root@localhost ~]# netperf -H 10.0.0.1 -t TCP_STREAM -l 300
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.0.0.1 (10.0.0.1) port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 300.00 3453.29
将netperf的客户端与服务端对换,再次进行5分钱带宽测试,结果如下:
[root@localhost ~]# netperf -H 10.0.0.2 -t TCP_STREAM -l 300
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.0.0.2 (10.0.0.2) port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 300.00 5701.31
2.3.数据对比
以下为简单直白的测试数据对比
是否开启NUMA感知 | 10.0.0.2 -> 10.0.0.1 | 10.0.0.1->10.0.0.2 |
---|---|---|
是 | 6063.37 | 5826.15 |
否 | 3453.29 | 5701.31 |
测试数据比较迷,从10.0.0.2向10.0.0.1打流提升很明显,但反过来就基本没差别了,这后面是什么原因还有待再观察
基本的猜测是由于10.0.0.1所属的虚拟机,其内存与ovs+dpdk同属于一个NUMA节点,这样10.0.0.1发送流量时,流量能更有效率的到达ovs。
3.更多的思考
首先开启了NUMA感知后性能看起来是有提升的,但这个数据比较迷,目前也说不好是为什么
其次,同一host内的虚拟机通信效率可能通过NUMA感知特性进行优化
如果是不同host下的虚拟机要进行通信效率的优化,可能还需要考虑到物理网卡与NUMA的关系
ovs+dpdk numa感知特性验证的更多相关文章
- 译文:ovs+dpdk中的“vHost User NUMA感知”特性
本文描述了"vHost User NUMA感知"的概念,该特性的测试表现,以及该特性为ovs+dpdk带来的性能提升.本文的目标受众是那些希望了解ovs+dpdk底层细节的人,如果 ...
- OVS+DPDK Datapath 包分类技术
本文主体内容译于[DPDK社区文档],但并没有逐字翻译,在原文的基础上进行了一些调整,增加了对TSS分类器的详细阐述. 1. 概览 本文描述了OVS+DPDK中的包分类器(datapath class ...
- OVS + dpdk 安装与实验环境配置
***DPDK datapath的OVS的安装与实验环境配置 首先肯定是DPDK的安装 0:安装必要的工具 make gcc ...
- OVS DPDK VXLAN隧道处理
原文链接: OVS DPDK VXLAN隧道处理
- Attribute特性验证模型model
数据验证我们往往分为前台验证和后台验证,而我们的后台验证每到一个方法中就要去验证一次,这样的代码想想都难以维护,这篇我们这篇文章就是为了解决这样的问题.用attribute 这个特性来解决这样的问题 ...
- [ovs][dpdk] ovs-dpdk, dpdk port 大量丢包
gdb了ovs的代码,发现是 dpdk的imiss计数在不断的丢包. 看了ovs-openvswitchd的日志,重启时发现如下行: --21T11::.427Z||timeval|WARN|Unre ...
- Nginx特性验证-反向代理/负载均衡/页面缓存/URL重定向
原文发表于cu:2016-08-25 参考文档: Nginx 反向代理.负载均衡.页面缓存.URL重写等:http://freeloda.blog.51cto.com/2033581/1288553 ...
- [ovs][dpdk] ovs-dpdk 线程数,收包队列,core绑定
http://docs.openvswitch.org/en/latest/intro/install/dpdk/?highlight=dpdk 绑定2,4,6, 8核 [root@vrouter1 ...
- 2017年2月28日-----------乱码新手自学.net 之特性与验证
现在看asp.net MVC5自学已经到了第六章:数据注解与验证. 话得从以前看MVC music store(音乐商店项目)的源码说起, 最初看music store源码完全就是一脸懵逼,整个程序, ...
随机推荐
- vuex使用报错
1.vuex简介 最近在玩vuex,不得不说它是一个很强大的工具,它的目的就是把数据统一管理起来,方便各个组件之间来回调用 2.vuex引用报错 当我们去官网看API文档的时候,会发现官网是这么应用a ...
- 最常用的缓存技术---redis入门
Redis简介 Redis是基于内存,也可以基于磁盘持久化nosql数据库,使用c语言开发. 数据存储结构:key-value 安装环境准备 Redis使用c语言开发,需要使用gcc编译程序进行编 ...
- 【JAVAWEB学习笔记】09_MySQL多表&JDBC(包含MySQL数据库思维导图)
今天晨读单词: order:订单constraint:(强制)约束foreign key:外键references:指向orderitem:订单项join:加入resourceBundle:资源捆绑c ...
- [转]GET,POST,PUT,DELETE的区别
原文链接:http://blog.csdn.net/mfe10714022/article/details/39692305 Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,P ...
- Day4-生成器generator
列表生成式 需求:列表[0,1,2,3,4,5,6,7,8,9]每个值加1,如何实现? 方法1:列表追加 >>> a = [0,1,2,3,4,5,6,7,8,9] >> ...
- .net操作InI文件
public class INI { public static string IniFileName = "";//路径 [DllImport("kernel32&qu ...
- 009一对一 主键关联映射_单向(one-to-one)
009一对一 主键关联映射_单向(one-to-one) ² 两个对象之间是一对一的关系,如Person-IdCard(人—身份证号) ² 有两种策略可以实现一对一的关联映射 主键关联:即让两个 ...
- tab切换插件开发
我开发的tab切换插件,基于jquery库,实现tab标签页的切换.插件的名称为jquery.tabSwitch.js. 插件实现代码如下: ; (function ($) { $.fn.tabSwi ...
- Creating beautiful charts in chinese with ggplot2
Before we start My chinese skills are poor and biased. I did learn during my internship and I contin ...
- abstract关键字
概念 abstract关键字表示的是抽象的意思,可以用来修饰类和方法.修饰类我们称为抽象类,修饰方法我们称为抽象方法. abstract修饰类,抽象类 1.public abstract clas ...