wKiom1kW1NWTtdnSAABvIoBICjU254.jpg

1.环境介绍

1.1测试简介

本次测试是针对KVM虚拟化在CPU、内存、磁盘、网络4大方面的全面性能测试与性能优化实践,目的在于通过对比测试,找出最适合我们所使用的硬件与软件架构的最佳优化配置,为OpenStack实现更高的性能提供支持。

 

1.2 硬件环境介绍

本次测试中,我们将通过OpenStack平台作为虚拟机管理工具,并且所有的用于测试的虚拟机都均运行在同一台物理机上

wKioL1kWyxDhqJ-PAAA4hIlzGck127.png


1.3 软件环境介绍

下面介绍一下本次测试的主机的软件环境:

wKioL1kWy1KgvU0mAAAxJvqW_yk695.png

以上就是本次KVM虚拟化测试所在主机的软件环境,其中值得注意的是KvmLibvirt的版本。


1.4 虚拟机测试用例

为了保证测试的科学严谨性,我们将选用同等规格的KVM虚拟机,在openstack中我们统一选用m1.small规格,即1vCPU2G内存、系统磁盘为20G

wKiom1kWy4rxqPZeAAAJZNmVK0g654.png

我们的虚拟机统一通过openstack来做创建、终止等操作,这样既保证了创建等操作不会因为人为操作失误而产生偏差,同时也使本次测试的结果为OpenStackHypervisor选型提供参考。


2. CPU部分

在虚拟化技术的发展过程中,我们可以看到也是CPU技术飞速发展的阶段,同时,这也说明了虚拟化对于CPU的要求是硬性的,即很难通过更加优秀的策略和算法来大量地提升性能。

但是,在这个追求高效低碳的时代,性能上的一点点提升都是值得我们去努力探索的。

 

2.1 虚拟机CPU性能将损失多少?

KVM虚拟化的CPU使用机制中,虚拟机的vCPU在虚拟机内部实现的各种调度对于宿主机的CPU是透明,每个vCPU对于物理CPU来说仅仅相当于一个进程,通过不同虚拟机不同优先级的情况来将CPU的核心分配给vCPU独占使用。

这样,我们不禁想知道,在KVM虚拟机中使用vCPU和宿主机中使用物理CPU,中间的性能损失有多少呢?

 

2.1.1 环境介绍

下面,我们将利用一个由C++编写的“找出1-1千万以内的质数”程序,在虚拟机和宿主机中分别进行测试,利用time工具查看他们分别需要多少的时间,以此来判断CPU的性能。

值得注意的是,我们的虚拟机分配了1vCPU,但是由于我们编写的测试程序是单线程的,所以在宿主机和虚拟机中运行都只能使用到1CPU核心,保证了测试的严谨性。

并且,该程序不会因为内存问题而使得宿主机和虚拟机的测试产生偏差,因为对于改程序来说其需要的内存在虚拟机上也是完全满足的。

以下是测试所用程序的源码:

#include<iostream>
#include<math.h>
using namespace std;
static int num=100000000;
int main(){
 
       bool *array=new bool[num+1];
       array[0]=false;
       array[1]=false;
       for(int i=2;i<=num;i++) array[i]=true;
       int b=int(pow(num,0.5))+1;
       int index=0;
       for(int j=2;j<=b;j++){
                index=2*j;
                while(index<=num){
                        array[index]=false;
                        index+=j;
                }
       }
       delete array;
       cout<<endl<<"===========Done!==========="<<endl;
       return 0;
}


2.1.2 测试分析

为了使数据更加有参考意义,我们将分别测试找出不同数量的质数,如1百万以内、1千万以内、1亿以内的质数。

首先,我们在虚拟机中运行测试程序:

wKioL1kWzA6A7LlTAAASHlexk1Q905.png

接下来,我们在宿主机运行测试程序:

wKiom1kWzBzBZOb5AAASmE_SVzE250.png

以上的测试数据都经过了3次测试,并且取平均值,以保证测试数据的可靠性。我们将以上两部分的测试结果汇总如下:

wKiom1kWzEKzxhH_AAAqXm6Hv6Y683.png

从以上数据我们可以看到在1百万和1千万两次测试中,虚拟机和宿主机的性能几乎是没有损失的,但是到了1亿数据测试时,在性能表现上出现了巨大的变化,针对这样的结果,我们在虚拟中利用vmstat监控CPU的状态。

wKiom1kWzF6iBCsmAAAp8jx3iz4678.png

上图是虚拟机中执行1千万数据测试的状态,在查找过程中,虚拟机CPU使用率大约在30%-50%CPU没有达到满负荷。

wKiom1kWzHiTeNE5AAAg4bb5t4Y096.png

上图是虚拟机执行1亿数据测试的vmstat状态,我们可以看到虚拟机CPU持续地保持在100%的负载,此时则说明该测试已经到了虚拟机CPU的性能天花板,这样的性能表现不是因为宿主机的资源抢占造成的。

为了证明虚拟机在1亿数据量时的性能下降不是宿主机资源抢占造成的,我们将同时在宿主机和虚拟机上运行测试程序。

以下是宿主机和虚拟机同时运行测试程序的测试数据:

wKiom1kWzKOjemZ4AAAz0ouuO0E881.png

从以上数据可知,宿主机与虚拟机同时运行时的表现和单独运行几乎是没有偏差的,而宿主机上的CPU为什么没有不会像虚拟机中那样满负荷呢?可能是由于CPU自身的调度机制,这里不深究。

由于1亿的数据量对于单vCPU的虚拟机来说已经到了性能瓶颈,不能对比体现虚拟机与宿主机使用CPU的性能损耗,故不能作为对比的数据。

wKioL1kWzM2TR8AhAAAyvlp1w1k577.png

wKioL1kWzPTS0NV8AABCsJEWuxA305.png

我们将以上的数据汇总并生成条形图,可以看到KVM虚拟机对于物理机的CPU损失非常小,这也是完全虚拟化最大的优点之一。


3. 内存部分

近年来的虚拟化技术的发展中,针对内存方面的探索明显比其他方面要多,因为内存往往决定了虚拟机的运行性能,当宿主机需要使用swap交换分区来为虚拟机分配内存的时候,则虚拟机的性能将急速下降。

下面我们针对应用面最广的KSM内存页共享和HugePage大页技术来进行性能测试分析和优化的实践。

 

3.1 虚拟机内存性能将损失多少?

3.1.1 环境介绍

在我们选用一款虚拟化产品之前,我们最希望了解的是虚拟机中的CPU与内存跟物理机相比,性能将损失多少,其损失的性能是我们所能接受的吗?

针对这样的问题,我们将对虚拟机和宿主机进行内存测试,我们采用了一款功能强大的内存质量测试工具:memtester。你可以指定要用于测试的内存大小,例如100Mmemtester会从可用内存中抓取100M内存,进行各项测试运算,包括随机值写入、乘法、除法、异或比较、与或运算等等。我们利用time工具统计内存测试完成的时间,通过比较时间来看内存性能。

 

3.1.2 测试分析

首先,我们需要在测试用虚拟机和宿主机中分别安装memtester软件:

# apt-get install memtester

我们分别抓取10M100M1000M的内存作为测试的内存大小,每个测试重复测试3次,取平均值。

以下是虚拟机中的测试数据:

wKioL1kWzZOieWlrAAAVc0sf_68591.png

以相同的方法在宿主机上测试,得到如下数据:

wKiom1kWzaKQEoSTAAAUyHbTm_Q259.png

将虚拟机和宿主机的测试数据汇总,得到如下表格,完成全部内存测试项目用时最少的表明性能越好。

wKiom1kWzcjxIPVpAAA3JHK6CAw721.png

wKioL1kWzfbgJxO0AAA1vA14dks982.png

以上是由测试数据生成的图表,我们可以看到,对于虚拟机来说,的确会对内存产生部分的性能损耗,对于KVM虚拟化来说,CPU的性能是十分微小的,因为KVM完全虚拟机的内部机制决定了它在CPU方面的表现,但是KVM的内存调度并没有太大的改进,完全虚拟化的内存调度不需要通过OS,而是直接由Hypervisor直接从内存中获取,这样的机制相比半虚拟化有部分的性能提升。

本次内存性能测试中,我们的结论是,KVM虚拟化产品的内存与物理机内存相比,其性能损失大约在10%以下,这样的表现对于虚拟化产品来说是比较出色的。


3.2 到底要不要开启KSM页共享?

3.2.1 环境介绍

KSMKernelSamepage Merging)即内存页共享机制。页共享早已有之,linux中称之为COW(copyon write)Linux 2.6.32内核之后又引入了KSMKSM的主要特性是可以让内核查找内存中完全相同的内存页然后将他们合并起来,并将合并后的内存页打上COW标记。KSMKVM环境有很重要的意义,当KVM上运行许多相同系统的虚拟机时,虚拟机之间将有许多内存页是完全相同的,特别是只读的加载在内存中的内核代码页,完全可以在虚拟机之间共享,从而减少虚拟机占用的内存资源,从而使得宿主机可以同时运行更多的虚拟机。

我们在宿主机上运行10个虚拟机,统一采用OpenStack中的Small硬件规格,在没有开启KSM的情况下,我们监控宿主机CPU的负载情况,之后开启KSM功能,并设置KSM持续刷新,同时继续监控宿主机CPU负载,以此对比得出KSM功能对CPU负载会有多大的影响。

 

3.2.2 测试分析

本次测试我们使用sar工具来实时查看宿主机的CPU负载信息,当10台虚拟机完全启动之后,我们在宿主机上运行一段时间的sar,抓取没有开启KSMCPU负载,取平均值。

首先,我们需要在OpenStack中利用Dashboard图形化界面从同一个镜像文件启动10台虚拟机实例。

wKioL1kWziej2qIqAAEeM2-5-RY002.png

全部的虚拟机实例启动完成之后,我们使用sar工具每个2秒一次CPU负载信息,抓取20次,将当前宿主机CPU空闲率取平均值。

wKioL1kWzqbSCCsJAAA5fGDJ7IQ397.png

最后得出,当前宿主机CPU空闲率为96.86%

 

接下来,我们开启KSM功能,在Debian中默认没有开启KSM功能,需要我们手动开启:

# echo 1 > /sys/kernel/mm/ksm/run

/sys/kernel/mm/ksm/目录就是KSM模块所在的位置,针对KSM的所有设置都只能在这里把数据echo进去,/sys/kernel/mm/ksm/run是用于控制是否开启KSM功能的文件,“1”表示开启,“0”表示关闭。

同时,/sys/kernel/mm/ksm/目录下还有很多其他的用于精细化配置的文件,例如/sys/kernel/mm/ksm/sleep_millisecs,此文件用于指定KSM查找相同内存页的时间间隔。

为了测试出KSM对于宿主机CPU负载的影响,我们将KSM查找相同内存页的时间间隔设置为“0”,即KSM会不停地在内存中查找有没有相同的内存页。设置方法如下:

# echo 0 >/sys/kernel/mm/ksm/sleep_millisecs

设置完成后,我们使用sar监控CPU负载的变化:

wKiom1kWzsLRIL80AAAz2R1efKk682.png

经过计算,当前宿主机CPU空闲率为95.12%

以下是关闭KSM和开启KSM情况下的CPU负载图表,这样能使我们更加直观地看出对比。

wKioL1kWzu6A2rYwAABRb2vwoA4125.png

我们可以得出,开启KSM之后会比关闭KSMCPU负载高1.74%。但是这样的数据是在宿主机的虚拟机数量较少,并且所有虚拟机都处于空闲状态,所以真实环境下负载的提高是跟虚拟机以及业务有关的,根据官方数据,在生产环境下开启KSM,其会占用的CPU负载大概为3%-10%

这是一个极限测试,但是在真实应用中,我们往往会根据宿主机的软件硬件情况设置不同的时间间隔,尽量减少KSM对宿主机CPU负载的负担,同时KSM项目组也在积极努力以使得KSM能占用更少的CPU

 

3.2.3 优化实践

做完以上的测试分析,新的问题马上浮出了水面:我们到底要不要开启KSM呢?

我们知道,KSM机制最根本的目的在于使得一个宿主机能尽可能多地运行更多的虚拟机。如果你的虚拟化架构需要运行尽量多的虚拟机,例如IDC商,那么开启KSM会是一个十分不错的选择;如果你更多的是追求虚拟机有更高的性能,内存不是你们的稀缺资源,并且不希望KSM加大了宿主机的负载,那么请关闭KSM

对于OpenStack的应用来说,往往运算节点上运行着众多由同一个镜像启动起来的虚拟机实例,这种情况开启KSM是十分有利的,并且根据我们的测试,KSM对于宿主机的影响是比较轻微的,我们可以根据宿主机的CPU性能、内存大小、预计运行虚拟机数量来设置KSM查找相同内存页的时间间隔,以此来控制KSM对宿主机的影响。

值得注意的是:国人对KSM做了进一步优化,发布了UKSM(UltraKSM)项目,据说比KSM扫描更全面,扫描页面速度更快,而且CPU占用率更低,目前此项目已经能在FedoraUbuntu的源中使用。

 

3.3 使用Huge Page能带来多少性能提升?

Huge Page,有人称为巨页,也可以称为大页。x86架构通常使用4K内存页,但也有能力使用更大的内存页,x86_32可以使用4MB内存页,x86_64x86_32PAE可以使用2MB内存页。

x86内存使用多级页表结构,一般有三级:页目录表、页表、页。我们通过使用大页,可以减少页目录表和页表对内存的消耗。通过为虚拟机提供大页的后端内存,可以减少虚拟机消耗的内存并提高内存TLB(页表缓存)命中率,从而提升KVM性能。

 

3.3.1 环境介绍

下面介绍一下测试环境。我们依然在hz188-139宿主机上进行全部的测试,虚拟机在OpenStack创建,规格为m1.Small

我们首先在没有配置HugePage的情况下,利用内存测试工具memtester对虚拟机中的内存进行测试,之后配置开启HugePage大页功能,再在虚拟机中做同样的测试,之后汇总结果进行分析。

每个测试测试3次,取平均值。

以下是我们在宿主机上配置HugePage大页的操作:

# mkdir /dev/hugepage

查看hugepage的相关内核参数:

# sysctl -a | grep -i huge 

wKiom1kWzw3i27BcAAAa-0JnX-U563.png

其中的“vm.nr_hugepages”参数是指用户大页的页面数,在设置我们要开启的大页数之前,需要查看一下当前系统HugePage的大小:

# cat /proc/meminfo | grep -i huge

我们可以看到当前系统的大页为2M,而设置开启大页数量是一门大学问,因为大页是常驻内存的,我们要严谨地分析、合理地规划,确保不会影响宿主机系统的性能,同时又让KVM能最大限度地使用大页。

我们将要设置的参数写入到sysctl.conf文件中:

# vi /etc/sysctl.conf

# sysctl -p | grep huge

接下来挂载hugepage虚拟文件系统:

# mount -t hugetlbfs hugetlbfs/dev/hugepage

为了使hugepage的设置开机自启动,我们需要把挂载信息写入到fatab中。

当我们需要创建KVM虚拟机的时候,我们需要手动地用“-mem-path”参数来指定hugepage虚拟文件系统的地址,让KVM通过hugepage获取内存。

在我们可以在/proc/meminfo中查看“HugePages_Total”和“HugePages_Free”项,可以直观地看到当前宿主机上hugepage的使用情况。

 

3.3.2 测试分析

我们的测试将利用memtester作为测试工具,在虚拟机内部,当我们需要使用内存时,KVM会通过一定的机制去申请获取物理内存,而普通情况下换入换出的内存页大小为4K,当我们设置使用大页之后,KVM虚拟机就会直接通过大页来申请内存,这时的内存页大小为2MMemtester中的内存质量测试都会是一样的,唯独在申请内存及使用时,普通的方式和通过大页的方式有所区别,所以我们可以通过完成memtester的时间作为一个衡量的标尺。

以下是普通内存分配方式下的测试数据:

wKioL1kWzz2g3vPjAAAmWSbJV6M840.png

以下是Huge Page内存分配方式下的测试数据:

wKioL1kWz6Sw98Y6AAAoXCaq3-g666.png

下面,我们将以上的两组数据汇总如下:

wKiom1kWz67wir5wAAA4n3JgZdM292.png

wKioL1kWz6_ABhR1AAA6oJEVric777.png


3.3.3 优化实践

根据以上的测试数据,我们可以看到使用了HugePage的内存分配机制之后,测试时间有了一定程度的缩短,这就说明hugepage比传统X86的内存页大得多而使得测试过程中节省了大量的内存页分配时间。

但是,设置Hugepage之后这部分的内存会直接被其占用管理,也就是说操作系统无法再对这部分内存做任何操作,所以在设置Hugepage的时候我们需要合理地做好规划,尽量提升Hugepage带来的优点。


4. 磁盘部分

相对于CPU和内存的发展步伐,硬盘技术的发展确实是不给力。所以在现今的企业IT架构中,往往磁盘I/O才是真正的瓶颈。对于虚拟化来说,磁盘性能也直接影响着虚拟机的性能。

下面我们将针对两种最常见的虚拟机磁盘镜像格式:Qcow2Raw,一个是COWCopyon Write)设备,一个是RAW设备。根据我们以往的了解,我们知道qcow2格式的镜像占用空间小,这也是所有COW设备的优点,而RAW设备则是完全的磁盘大小,但是据说读写性能优于Qcow2

下面就让我们通过严谨的测试分析,找到最适合我们使用的镜像格式,从而整体提升OpenStack的性能。

 

4.1 Qcow2Raw哪个最适合我们?

4.1.1 环境介绍

本次测试我们主要围绕着从虚拟机中读取和写入数据时,不同磁盘文件的读写性能表现。我们将在同一台宿主机上开启两台完全相同规格的虚拟机,他们采用统一的镜像,只是利用qemu-img转换了镜像的格式。

我们分别以100M500M1000M为单位在不同格式的虚拟机上做读取数据和写入数据的操作,利用time统计操作的时间,以此来对比不同磁盘格式的虚拟机读写数据的性能。


4.1.2 测试分析

Qcow2磁盘格式的虚拟机中,我们利用dd工具从随机数中写入到某个文件中,通过time来统计完成时间。

以下是测试数据统计表:

wKiom1kW0QvBsPUGAAAxQmti6PM485.png

接下来,我们在RAW磁盘格式的虚拟机中执行相同的测试,利用time统计完成时间,数值越小表示性能越好,数据如下:

wKioL1kW0RWjK2j5AAAwmsupHUM213.png

根据以上两种磁盘格式的测试结果,我们可以将数据汇总起来,并形成更加直观的图表:

wKioL1kW0R-Td_jrAAAwnnv28R8026.png

wKiom1kW0T_gOiopAABINBmz_1s920.png

将两种磁盘格式的读性能数据汇总起来,形成图表如上。

可以看到RAW格式的读性能是完全优于Qcow2格式的,所以如果我们的镜像存储不再需要考虑镜像占用空间大小的话,RAW格式可以提供更加优秀的读性能。

wKioL1kW0ayif7FAAAAzC5KkTrE695.png

wKiom1kW0azzVnXSAABDTUXcadI546.png

将两种磁盘格式的写性能数据汇总起来,形成图表如上。

相对于读性能的差距,写性能的对比相对没有这么明显,但是在写性能方面,依然是RAW格式具有更好的性能。


4.1.3 优化实践

根据以上的读写测试与分析,我们可以知道RAW设备是优于Qcow2设备的,但是我们考虑技术的选型不应该仅仅从性能出发,例如当我们需要考虑到镜像存储的容量问题时、当我们需要考虑虚拟机启动加载问题时,在Openstack中运算节点启动虚拟机需要先从镜像池中拷贝一份备份,之后再从运算节点上启动,这样Qcow2格式的特点显然能使启动速度提升一个档次。

具体的选型需要全面的分析和规划。


5. 网络部分

对于所有的虚拟化来说,其所获得的资源都是来自硬件的,只是利用资源利用的机制,提高了资源利用率。同样地,虚拟化的网络性能与宿主机的网卡性能和吞吐率也是直接关联的,所以在网络方面我们可以调整的并不多。

下面我们将针对KVM中的virtIO驱动器进行测试,KVM默认的I/O驱动为IDE,而virtIO驱动由于其机制上的创新而具有更高的性能,那么virtIO究竟能为我们提升多少性能呢?


5.1 VirtIO究竟有多大能耐?

首先,大家一定很想知道什么是virtIO

虚拟化的方方面面都在高速发展,唯有I/O部分始终难以突破。如何让Hypervisor能够在I/O虚拟化方面充分地利用底层内核呢?答案是使用virtio驱动,它为hypervisor提供一组通用的 I/O 虚拟化驱动程序,提供高效的抽象。

wKioL1kW0dPTdSzTAAD5Gm21FLw495.png

如上图,VirtIO其实是一个基于半虚拟化的产品,在KVM的应用中,virtIO会在Qemu空间内为虚拟机提供一个I/O虚拟的前端,而在Hypervisor上提供一个后端和设备虚拟的功能,这样虚拟机与宿主机之间的I/O通信就不再是通过Hypervisor的物理信号模拟(效率低),而是通过virtIO的机制进行通信,大大提高了I/O效率。


5.1.1 环境介绍

本次测试我们将分为虚拟机与物理机之间的数据传输、虚拟机与虚拟机之间的数据传输。当然,本次测试环境中虚拟机与物理机都是处于同一个局域网的,保证测试环境的一致性。


5.1.2 测试分析

下面,我们首先在不开启virtIO的情况下做数据传输测试,我们利用dd命令创建了一个1G大小的文件,我们将使用scp命令进行传输,利用time工具计算整个传输过程所使用的时间,之后计算出本次传输的平均传输速率。

以下是未使用VirtIO驱动的测试数据:

wKioL1kW0ruzJ62pAAAqUz6U2TM990.png

以下是使用了VirtIO驱动的测试数据:

wKiom1kW0sfBZdZOAAAonl0GXIE646.png

wKioL1kW0seBGrObAAA9Ni80z6U043.png

我们将上面两组数据进行汇总,得到如上数据对比表。通过传输的速率我们可以看到,使用了VirtIO之后的传输速率得到了惊人的提升,下面我们将数据形成图表,如下。

wKioL1kW0uuSw6q7AABBRIzgW3k355.png

根据以上的图表,我们看到开启VirtIO之后,无论是虚拟机与虚拟机、物理机与虚拟机之间的数据传输速率相差不多,这也是VirtIO的主要特点之一。在我们本次测试中,传输速率大概在27MB/s,这样速度在千兆网卡的环境下已经是超凡的表现了。


5.1.3 优化实践

根据以上的测试和分析,我们知道使用VirtIO驱动是有百利无一害的,因为VirtIO的机制使得KVM这类完全虚拟化产品最大的弊端以及企业级应用中最大的瓶颈得到解决。

所以在OpenStack系统中,我们需要在nova.conf主配置文件中加入VirtIO的相关参数“libvirt_use_virtio_for_bridges=True”,这样将为各节点之间连接的网桥启用VirtIO,极大提升I/O性能。


6. 总结

至此,本次KVM虚拟化性能测试与优化实践完结了。通过本次CPU、内存、磁盘、网络4方面的测试分析,我们更加深入地了解了KVM的性能,同时也找到了一些适合生产环境使用的强悍的技术。

性能优化的工作并不是做简单的性能测试,更重要的是在实际的生产环境中,在真实的线上压力下,全面测试性能和稳定性,根据我们业务的需求找到最适合我们的技术,这才是性能优化的根本宗旨。