注:本文是参照了一些其他文章,原文地址点击这里
概念
首先说NUMA(non-uniform memory access),他的引入是为了解决CPU、内存和IO等扩展性的问题,他用node进行区分,每个node都有自己独立的CPU、本地内存和IO槽口等。他们通过互联模块进行连接和信息交互,因为任意一个CPU都可以访问整个系统的内存,但是访问速度就差距很大了,本地节点>邻居节点>远端节点。所以扩展的越多,访问远端的节点耗费时间越长,而我们要做的尽量让每个CPU都处理本地的内存数据。
接下来说DPDK中的NUMA,DPDK从2.2版本引入了NUMA的概念,为了更好的应用在ovs-dpdk中,我们首先需要理解vhost-user设备包含的3中类型的内存:
* | Memory managed by | Description |
---|---|---|
1 | DPDK | Device tracking memory |
2 | OVS | Backend buffers (mbufs) |
3 | QEMU | Guest memory (device and memory buffers) |
对于一个已经优化了的datapath,所有以上的三种类型内存都需要分配在同一个节点上。在DPDK2.2之前这是不可能实现的,因为每一个DPDK管理的设备都必须存在于同一个节点上,而VM使用的Guest memory就可能不会在同一个节点上,这就造成了如下图Intel QPI(QuickPath Interconnect)流量和潜在的性能问题。
DPDK 2.2之后,vhost结构和Guest memory进行了动态关联,当vhost设备申请时,他是临时存储的,当他连接的VM的Guest memory的信息通过qemu传递给DPDK。DPDK利用该信息将vhost设备也驻留在该NUMA的节点。
之前我们没有提及的时mbufs,也就是ovs分配的内存,他必须和Guest memory和Device tracking memroy在相同的节点。DPDK通过讲guest的信息发送给ovs,然后ovs在相应的节点申请mbufs。在这之前,mbufs都是存在于DPDK的master lcore所在节点。
最后的一个难题就是关于OVS的PMD(poll mode driver)线程的位置。PMD是负责轮询所有的输入端口,一旦收到数据就会进行一系列的操作。以前ovs的PMD线程都必须固定在同一个NUMA节点的lcore上,该节点就是DPDK的mater lcore。但是现在PMD线程可以放置在和Device tracking memory、Guest memory相同的节点上,如下图所示:
其实这个我们可以看到至少需要两个PMD线程,也就是每个NUMA需要一个PMD的线程,需要两个lcore,这就需要我们自己去评估有没有必要使用这么多的CPU。
测试环境
测试环境需要至少有两个NUMA节点的主机,主机运行ovs-dpdk,并且为ovs-dpdk配置两个vhostuser设备。两个VM在两个单独的NUMA节点上,分别链接两个vhostuser设备,如下表所示:
Processor | Intel® Xeon® processor E5-2695 v3 @ 2.30 GHz |
---|---|
Kernel | 4.2.8-200 |
OS | Fedora* 22 |
QEMU* | v2.6.0 |
DPDK | v16.04 |
Open vSwitch* | 914403294be2 |
配置
安装DPDK和OVS之前,确保NUMA的一些库已经安装了
sudo yum install numactl-libs
sudo yum install numactl-devel
DPDK的配置做如下改动
CONFIG_RTE_LIBRTE_VHOST_NUMA=y
按照上面的介绍,ovs的两个PMD线程要跑在两个NUMA节点上,我们核心0-13位于NUMA节点0,14-27位于NUMA节点1上,所以我们需要配置ovs的PMD线程绑定lcore的掩码
ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=10001
运行虚拟机之前,可以确认一下PMD线程,确认vhostuser的Device tracking memory和PMD线程位于同一个NUMA节点上
ovs-appctl dpif-netdev/pmd-rxq-show
pmd thread numa_id 0 core_id 0:
port: dpdkvhostuser1 queue-id: 0
port: dpdkvhostuser0 queue-id: 0
接下来启动两个VM,使用taskset来确认两个VM分别位于两个NUMA节点上
sudo taskset 0x2 qemu-system-x86_64 -name VM0 -cpu …
sudo taskset 0x2000 qemu-system-x86_64 –name VM1 -cpu …
检查VM的日志,VM1打印的信息如下:
VHOST_CONFIG: read message VHOST_USER_SET_VRING_ADDR
VHOST_CONFIG: reallocate vq from 0 to 1 node
VHOST_CONFIG: reallocate dev from 0 to 1 node
这意味着Device tracking memory已经从之前的临时存储在节点0,切换到指定的节点1了。
另一种验证成功的方式就是通过使用pmd-rxq-show
检查PMD
pmd thread numa_id 1 core_id 20:
port: dpdkvhostuser1 queue-id: 0
pmd thread numa_id 0 core_id 0:
port: dpdkvhostuser0 queue-id: 0
dpdkvhostuser1
运行的线程是在NUMA节点1。