Chinaunix首页 | 论坛 | 博客
  • 博客访问: 10222590
  • 博文数量: 1669
  • 博客积分: 16831
  • 博客等级: 上将
  • 技术积分: 12594
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-25 07:23
个人简介

柔中带刚,刚中带柔,淫荡中富含柔和,刚猛中荡漾风骚,无坚不摧,无孔不入!

文章分类

全部博文(1669)

文章存档

2023年(4)

2022年(1)

2021年(10)

2020年(24)

2019年(4)

2018年(19)

2017年(66)

2016年(60)

2015年(49)

2014年(201)

2013年(221)

2012年(638)

2011年(372)

分类: 虚拟化

2016-03-21 10:40:37

kvm性能优化方案


kvm性能优化,主要集中在cpu、内存、磁盘、网络,4个方面,当然对于这里面的优化,也是要分场景的,不同的场景其优化方向也是不同的,下面具体聊聊这4个方面的优化细节。

cpu

在介绍cpu之前,必须要讲清楚numa的概念,建议先参考如下两篇文章

CPU Topology

玩转cpu-topology

查看cpu信息脚本:


001.#!/bin/bash
002.  
003.# Simple print cpu topology
004.# Author: kodango
005.  
006.function get_nr_processor()
007.{
008.    grep '^processor' /proc/cpuinfo | wc -l
009.}
010.  
011.function get_nr_socket()
012.{
013.    grep 'physical id' /proc/cpuinfo | awk -F: '{
014.            print $2 | "sort -un"}' | wc -l
015.}
016.  
017.function get_nr_siblings()
018.{
019.    grep 'siblings' /proc/cpuinfo | awk -F: '{
020.            print $2 | "sort -un"}'
021.}
022.  
023.function get_nr_cores_of_socket()
024.{
025.    grep 'cpu cores' /proc/cpuinfo | awk -F: '{
026.            print $2 | "sort -un"}'
027.}
028.  
029.echo '===== CPU Topology Table ====='
030.echo
031.  
032.echo '+--------------+---------+-----------+'
033.echo '| Processor ID | Core ID | Socket ID |'
034.echo '+--------------+---------+-----------+'
035.  
036.while read line; do
037.    if [ -z "$line" ]; then
038.        printf '| %-12s | %-7s | %-9s |\n' $p_id $c_id $s_id
039.        echo '+--------------+---------+-----------+'
040.        continue
041.    fi
042.  
043.    if echo "$line" | grep -q "^processor"; then
044.        p_id=`echo "$line" | awk -F: '{print $2}' | tr -d ' '` 
045.    fi
046.  
047.    if echo "$line" | grep -q "^core id"; then
048.        c_id=`echo "$line" | awk -F: '{print $2}' | tr -d ' '` 
049.    fi
050.  
051.    if echo "$line" | grep -q "^physical id"; then
052.        s_id=`echo "$line" | awk -F: '{print $2}' | tr -d ' '` 
053.    fi
054.done < /proc/cpuinfo
055.  
056.echo
057.  
058.awk -F: '{ 
059.    if ($1 ~ /processor/) {
060.        gsub(/ /,"",$2);
061.        p_id=$2;
062.    } else if ($1 ~ /physical id/){
063.        gsub(/ /,"",$2);
064.        s_id=$2;
065.        arr[s_id]=arr[s_id] " " p_id
066.    }
067.
068.  
069.END{
070.    for (i in arr) 
071.        printf "Socket %s:%s\n", i, arr[i];
072.}' /proc/cpuinfo
073.  
074.echo
075.echo '===== CPU Info Summary ====='
076.echo
077.  
078.nr_processor=`get_nr_processor`
079.echo "Logical processors: $nr_processor"
080.  
081.nr_socket=`get_nr_socket`
082.echo "Physical socket: $nr_socket"
083.  
084.nr_siblings=`get_nr_siblings`
085.echo "Siblings in one socket: $nr_siblings"
086.  
087.nr_cores=`get_nr_cores_of_socket`
088.echo "Cores in one socket: $nr_cores"
089.  
090.let nr_cores*=nr_socket
091.echo "Cores in total: $nr_cores"
092.  
093.if [ "$nr_cores" = "$nr_processor" ]; then
094.    echo "Hyper-Threading: off"
095.else
096.    echo "Hyper-Threading: on"
097.fi
098.  
099.echo
100.echo '===== END ====='

相信通过上面两篇文章,基本已经可以搞清楚node、socket、core、logic processor的关系,可以知道内存、l3-cache、l2-cache、l1-cache和cpu的关系。


针对kvm的优化,一般情况,都是通过pin,将vm上的cpu绑定到某一个node上,让其共享l3-cache,优先选择node上的内存,bind方法可以通过virt-manage processor里面的pinning动态绑定。这个绑定是实时生效的。

由于没有下载到speccpu2005,所以写了个大量消费cpu和内存的程序,来检验绑定cpu所带来的性能提升,程序如下:


01.#include
02.#include
03.#include
04.  
05.#define BUF_SIZE  512*1024*1024
06.#define MAX 512*1024
07.#define COUNT 16*1024*1024
08.  
09.char * buf_1 = NULL;
10.char * buf_2 = NULL;
11.  
12.  
13.void *pth_1(void *data)
14.{
15.        char * p1 = NULL;
16.        char * p2 = NULL;
17.    int value1 = 0;
18.    int value2 = 0;
19.    int value_total = 0;
20.    int i = 0;
21.    int j = 0;
22.    for (i = 0; i <=COUNT; i++) {
23.            value1 = rand() % (MAX + 1);
24.            value2 = rand() % (MAX + 1);
25.            p1 = buf_1 + value1*1024;
26.            p2 = buf_2 + value2*1024;
27.            for (j = 0; j < 1024; j++) {
28.                    value_total += p1[j];
29.                    value_total += p2[j];
30.            }
31.    }
32.    return NULL;
33.}
34.  
35.void *pth_2(void *data)
36.{
37.        char * p1 = NULL;
38.        char * p2 = NULL;
39.    int value1 = 0;
40.    int value2 = 0;
41.    int value_total = 0;
42.    int i = 0;
43.    int j = 0;
44.    for (i = 0; i <=COUNT; i++) {
45.            value1 = rand() % (MAX + 1);
46.            value2 = rand() % (MAX + 1);
47.            p1 = buf_1 + value1*1024;
48.            p2 = buf_2 + value2*1024;
49.            for (j = 0; j < 1024; j++) {
50.                    value_total += p1[j];
51.                    value_total += p2[j];
52.            }
53.    }
54.    return NULL;
55.}
56.  
57.  
58.int main(void)
59.{
60.      
61.        buf_1 = (char *)calloc(1, BUF_SIZE);
62.        buf_2 = (char *)calloc(1, BUF_SIZE);
63.        memset(buf_1, 0, BUF_SIZE);
64.        memset(buf_2, 0, BUF_SIZE);
65.          
66.    pthread_t th_a, th_b;
67.    void *retval;
68.    pthread_create(&th_a, NULL, pth_1, 0);
69.    pthread_create(&th_b, NULL, pth_2, 0);
70.  
71.    pthread_join(th_a, &retval);
72.    pthread_join(th_b, &retval);
73.    return 0;
74.}

我的实验机器上,偶数cpu在node 0 上,奇数cpu在node 1上,vm有2个cpu,程序有2个线程,分别将vm绑定到8,9和10,12,通过time命令运行程序,time ./test,测试结果如下
01.8,9
02.real    1m53.999s
03.user    3m34.377s
04.sys 0m3.020s
05.  
06.10,12
07.real    1m25.706s
08.user    2m49.497s
09.sys 0m0.699s
可以看出,绑定到同一个node上,比绑到不同node上其消耗时间小不少。测试过程中,也发现如果提供8、9、10、11的cpu,系统会在大部分时间选择8、10和9、11,所以猜测,kvm在cpu bind上,可能已经做了优化,会尽可能的往同一个node上绑定。


这里需要注意的一点是,通过virt-manage pin cpu,仅仅进行cpu bind,会共享l3-cache,并没有限制一定用某一个node上的内存,所以仍然会出现跨node使用内存的情况。

内存

优化项包括EPT、透明大页、内存碎片整理、ksm,下面一个一个来介绍

EPT

针对内存的使用,存在逻辑地址和物理地址的转换,这个转换时通过page table来进行的,并且转换过程由cpu vmm硬件加速,速度是很块的。

但是引入vm之后,vm vaddr----->vm padddr--------->host paddr,首先vm需要进行逻辑地址和物理地址的转换,但是vm的物理地址还是host机的逻辑地址,所以需要再进行一次逻辑地址到物理地址的转换,所以这个过程有2次地址转换,效率非常低。

幸亏intel提供了EPT技术,将两次地址转换变成了一次。这个EPT技术是在bios中,随着VT技术开启一起开启的。

透明大页

逻辑地址向物理地址的转换,在做转换时,cpu保持一个翻译后备缓冲器TLB,用来缓存转换结果,而TLB容量很小,所以如果page很小,TLB很容易就充满,这样就很容易导致cache miss,相反page变大,TLB需要保存的缓存项就变少,减少cache miss。

透明大页的开启:echo always > /sys/kernel/mm/transparent_hugepage/enabled

内存碎片整理的开启:echo always> /sys/kernel/mm/transparent_hugepage/defrag

KSM

文章http://blog.chinaunix.net/uid-20794164-id-3601786.html,介绍的很详细,简单理解就是可以将内容相同的内存合并,节省内存的使用,当然这个过程会有性能损耗,这个需要考虑使用场景,如果不注重vm性能,而注重host内存使用率,可以考虑开启,反之则关闭,在/etc/init.d/下,服务名称为ksm和ksmtuned。

磁盘

磁盘的优化包括:virtio-blk、缓存模式、aio、块设备io调度器

virtio

半虚拟化io设备,针对cpu和内存,kvm全是全虚拟化设备,而针对磁盘和网络,则出现了半虚拟化io设备,目的是标准化guest和host之间数据交换接口,减少交换流程,减少内存拷贝,提升vm io效率,可以在libvirt xml中设置,disk中加入

缓存模式

从vm写磁盘,有3个缓冲区,guest fs page cache、Brk Driver writeback cache、Host FS page cache,在host上的设置,无法改变guest fs page cache,但是可以改变后来个cache,缓存模式有如下5种,当采用Host FS page cache,会有一个写同步,会实时将cache中的数据flush到磁盘上,当然这样做比较安全,不会丢失数据。具体模式见下图。

第1和第5种,很少会有人使用,都比较极端,中间3种,其性能比较如下:

可以看出writeback mode在mail server这种,小文件 高io的服务器其性能是很差的,none模式大部分情况要比writethrough性能稍好一点,选择none。

启用方式在libvirt xml disk中加入

aio

异步读写,分别包括Native aio: kernel AIO 和 threaded aio: user space AIO emulated by posix thread workers,内核方式要比用户态的方式性能稍好一点,所以一般情况都选择native,开启方式

块设备调度器

cfq:perprocess IO queue,较好公平性,较低aggregate throughput

deadline:per-device IO queue,较好实时性,较好aggregate throughput,不够公平,容易出现VM starvation

这个目前笔者还没有做过测试,但是查看网易和美团云的方案,其都将其设置为cfq。

开启方式:echo cfq > /sys/block/sdb/queue/scheduler

网络

优化项包括virtio、vhost、macvtap、vepa、SRIOV 网卡,下面有几篇文章写的非常好

https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_/6/html-single/Virtualization_Tuning_and_Optimization_Guide/index.html#chap-Virtualization_Tuning_Optimization_Guide-Networking

http://www.ibm.com/developerworks/cn/linux/1312_xiawc_linuxvirtnet/

http://xiaoli110.blog.51cto.com/1724/1558984

virtio:更改虚拟网卡的类型,由全虚拟化网卡e1000、rtl8139,转变成半虚拟化网卡virtio,virtio需要qemu和vm内核virtio驱动的支持

vhost_net:vhost_net将virtiobackend处理程序由user space转入kernelspace,将减少两个空间内存拷贝和cpu的切换,降低延时和提高cpu使用率

macvtap:代替传统的tap+bridge,有4中模式,bridge、vepa、private、passthrough
1, Bridge, 完成与 Bridge 设备类似功能,数据可以在属于同一个母设备的子设备间交换转发. 当前的实现有一个缺陷,此模式下MACVTAP子设备无法和Linux Host通讯,即虚拟机无法和Host通讯,而使用传统的Bridge设备,通过给Bridge设置IP可以完成。但使用VEPA模式可以去除这一限制. macvtap的这种bridge模式等同于传统的tap+bridge的模式.
2, VEPA, 式是对802.1Qbg标准中的VEPA机制的部分软件实现,工作在此模式下的MACVTAP设备简单的将数据转发到母设备中,完成数据汇聚功能,通常需要外部交换机支持Hairpin模式才能正常工作。
3, Private, Private模式和VEPA模式类似,区别是子 MACVTAP之间相互隔离。
4, Passthrough, 可以配合直接使用SRIOV网卡, 内核的MACVLAN数据处理逻辑被跳过,硬件决定数据如何处理,从而释放了Host CPU资源。MACVTAP Passthrough 概念与PCI Passthrough概念不同,PCI Passthrough针对的是任意PCI设备,不一定是网络设备,目的是让Guest OS直接使用Host上的 PCI 硬件以提高效率。MACVTAP Passthrough仅仅针对 MACVTAP网络设备,目的是饶过内核里MACVTAP的部分软件处理过程,转而交给硬件处理。综上所述,对于一个 SRIOV 网络设备,可以用两种模式使用它:MACVTAP Passthrough 与 PCI Passthrough

PCIpass-through:直通,设备独享。

SO-IOV:优点是虚拟网卡的工作由hostcpu交给了物理网卡来实现,降低了hostcpu的使用率,缺点是,需要网卡、主板、hypervisor的支持。

这几种优化方案,其关系可以由下面这张图来表示。

总结来看网络虚拟化具有三个层次:

1, 用户可以零成本地使用 Linux 软件实现的 Bridge、VLAN、MACVTAP设备定制与现实世界类似的虚拟网络;
2, 也可以用非常低的成本按照802.1Qbg中的VEPA模型创建升级版的虚拟网络,引出虚拟机网络流量,减少Host服务器负载;
3, 当有支持 SRIOV 的网卡存在时,可以使用 Passthrough 技术近一步减少Host负载

总结:文章总共阐述了cpu、内存、磁盘、网络的性能优化方案,大部分都是通过kvm参数和系统内核参数的修改来实现。

KVM全功能虚拟化性能优化方案

作者:join12  发布日期:2012-12-30 11:03:14
可从以下几个方面优化KVM虚拟机,提高虚拟机的性能。
 
1、全虚拟化使用半虚拟化驱动(virtio)
    virtio是KVM的半虚拟化机制,可提高IO性能,使用virtio可心显著提高KVM性能。virtio包括磁盘驱动和网卡驱动,下面是在XML文件中的使用方法:
磁盘配置文件:
   
     
     
     
   
网卡配置文件:
   
     
     
     
     
   

 
2、使用writeback缓存选项
针对客户机块设备的缓存,drive有一个子选项cache来设置缓存模式。两个主要的选项为writeback和writethrough,man手册是这样说的
By default, writethrough caching is used for all block device. This means that the host page cache will be used to read and write data but write notification will be sent to the guest only when the data has been reported as written by the storage subsystem.
Writeback caching will report data writes as completed as soon as the data is present in the host page cache. This is safe as long as you trust your host. If your host crashes or loses power, then the guest may experience data corruption.
writethrough写操作时不使用主机的缓存,只有当主机接受到存储子系统写操作通知时,宿主机才通知客户机写操作,也就是说这是同步的。而writeback则是异步的,它是当客户机有写请求时,先将数据写入宿主机缓存,而此时主机并未将数据真正写入存储系统。之后,待合适的时机主机会真正的将数据写入存储。显然writeback会更快。
这样使用writeback选项:
   
     
     
     
   
 
3、客户机的磁盘IO调度策略
    客户机上的磁盘只不过是宿主机的一个文件,所以其IO调度并无太大意义,反而会影响IO效率,所以可以通过将客户机的IO调度策略设置为NOOP来提高性能。NOOP就是一个FIFO队列,不做IO调度。可以通过给内核传递一个参数来使用NOOP调度策略
    编辑文件/boot/grub/grub.conf,在kernel那行加入elevator=noop
   
    宿主机调度方式改为:deadline deadline是通过时间以及硬盘区域进行分类,这个分类和合并要求类似于noop的调度程序。确保了在一个截止时间内服务请求,默认读期限短于写期限.这样就防止了写操作因为不能被读取而饿死的现象。
   
4、打开KSM(Kernel Samepage Merging)
    页共享在内核2.6.32之后又引入了KSM。KSM特性可以让内核查找内存中完全相同的内存页然后将他们合并,并将合并后的内存页打上COW标记。KSM对KVM环境有很重要的意义,当KVM上运行许多相同系统的客户机时,客户机之间将有许多内存页是完全相同的,特别是只读的内核代码页完全可以在客户机之间共享,从而减少客户机占用的内存资源,从而可以同时运行更多的客户机。
centos默认没有开启KSM,如果KVM要使用KSM那必要安装:qemu-common。
开启KSM服务:service ksm start
            service ksmtuned start
通过/sys/kernel/mm/ksm目录下的文件来查看内存页共享的情况,pages_shared文件中记录了KSM共享的总页面数,pages_sharing文件中记录了当前共享的页面数。每个页面的大小为4KB 可计算出共享内在为:4X页面数=内存大小(K)
KSM会稍微的影响系统性能,以效率换空间,如果系统的内存很宽裕,则无须开启KSM,如果想尽可能多的并行运行KVM客户机,则可以打开KSM。
 
5、KVM Huge Page Backed Memory
    通过为客户机提供巨页后端内存,减少客户机消耗的内存并提高TLB命中率,从而提升KVM性能。x86 CPU通常使用4K内存页,但也有能力使用更大的内存页,x86_32可以使用4MB内存页,x86_64和x86_32 PAE可以使用2MB内存页。x86使用多级页表结构,一般有三级,页目录表->页表->页,所以通过使用巨页,可以减少页目录表和也表对内存的消耗。当然x86有缺页机制,并不是所有代码、数据页面都会驻留在内存中。
首先挂装hugetlbfs文件系统
#mkdir /hugepages
#mount -t hugetlbfs hugetlbfs /hugepages
然后指定巨页需要的内存页面数
#sysctl vm.nr_hugepages=xxx
客户机的XML配置文件使用巨页来分配内存:
 
 
 
或用命令行方式:
qemu-kvm -mem-path /hugepages
让系统开机自动挂载hugetlbfs文件系统,在/etc/fstab中添加
hugetlbfs /hugepages hugetlbfs defaults 0 0
在/etc/sysctl.conf中添加如下参数来持久设定巨页文件系统需要的内存页面数 
vm.nr_hugepages=xxx
巨页文件系统需要的页面数可以由客户机需要的内存除以页面大小也就是2M来大体估算。
查看巨页内存信息:cat /proc/meminfo |grep Hug
    AnonHugePages:     253120 kB
    HugePages_Total:   2000
    HugePages_Free:    904
    HugePages_Rsvd:     0
    HugePages_Surp:     0
    Hugepagesize:      2048 kB
 

阅读(1743) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~