kvm性能優化方案---cpu/內存/磁盤/網絡

kvm性能優化方案

kvm性能優化,主要集中在cpu、內存、磁盤、網絡,4個方面,當然對於這裏面的優化,也是要分場景的,不同的場景其優化方向也是不同的,下面具體聊聊這4個方面的優化細節。

cpu

在介紹cpu之前,必須要講清楚numa的概念,建議先參考如下兩篇文章

CPU Topology

玩轉cpu-topology

查看cpu信息腳本:

#!/bin/bash

# Simple print cpu topology
# Author: kodango

function get_nr_processor()
{
    grep '^processor' /proc/cpuinfo | wc -l
}

function get_nr_socket()
{
    grep 'physical id' /proc/cpuinfo | awk -F: '{
            print $2 | "sort -un"}' | wc -l
}

function get_nr_siblings()
{
    grep 'siblings' /proc/cpuinfo | awk -F: '{
            print $2 | "sort -un"}'
}

function get_nr_cores_of_socket()
{
    grep 'cpu cores' /proc/cpuinfo | awk -F: '{
            print $2 | "sort -un"}'
}

echo '===== CPU Topology Table ====='
echo

echo '+--------------+---------+-----------+'
echo '| Processor ID | Core ID | Socket ID |'
echo '+--------------+---------+-----------+'

while read line; do
    if [ -z "$line" ]; then
        printf '| %-12s | %-7s | %-9s |\n' $p_id $c_id $s_id
        echo '+--------------+---------+-----------+'
        continue
    fi

    if echo "$line" | grep -q "^processor"; then
        p_id=`echo "$line" | awk -F: '{print $2}' | tr -d ' '` 
    fi

    if echo "$line" | grep -q "^core id"; then
        c_id=`echo "$line" | awk -F: '{print $2}' | tr -d ' '` 
    fi

    if echo "$line" | grep -q "^physical id"; then
        s_id=`echo "$line" | awk -F: '{print $2}' | tr -d ' '` 
    fi
done < /proc/cpuinfo

echo

awk -F: '{ 
    if ($1 ~ /processor/) {
        gsub(/ /,"",$2);
        p_id=$2;
    } else if ($1 ~ /physical id/){
        gsub(/ /,"",$2);
        s_id=$2;
        arr[s_id]=arr[s_id] " " p_id
    }
} 

END{
    for (i in arr) 
        printf "Socket %s:%s\n", i, arr[i];
}' /proc/cpuinfo

echo
echo '===== CPU Info Summary ====='
echo

nr_processor=`get_nr_processor`
echo "Logical processors: $nr_processor"

nr_socket=`get_nr_socket`
echo "Physical socket: $nr_socket"

nr_siblings=`get_nr_siblings`
echo "Siblings in one socket: $nr_siblings"

nr_cores=`get_nr_cores_of_socket`
echo "Cores in one socket: $nr_cores"

let nr_cores*=nr_socket
echo "Cores in total: $nr_cores"

if [ "$nr_cores" = "$nr_processor" ]; then
    echo "Hyper-Threading: off"
else
    echo "Hyper-Threading: on"
fi

echo
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所帶來的性能提升,程序如下:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

#define BUF_SIZE  512*1024*1024
#define MAX 512*1024
#define COUNT 16*1024*1024

char * buf_1 = NULL;
char * buf_2 = NULL;


void *pth_1(void *data)
{
		char * p1 = NULL;
		char * p2 = NULL;
    int value1 = 0;
    int value2 = 0;
    int value_total = 0;
    int i = 0;
    int j = 0;
    for (i = 0; i <=COUNT; i++) {
    		value1 = rand() % (MAX + 1);
    		value2 = rand() % (MAX + 1);
    		p1 = buf_1 + value1*1024;
    		p2 = buf_2 + value2*1024;
    		for (j = 0; j < 1024; j++) {
    				value_total += p1[j];
    				value_total += p2[j];
    		}
    }
    return NULL;
}

void *pth_2(void *data)
{
		char * p1 = NULL;
		char * p2 = NULL;
    int value1 = 0;
    int value2 = 0;
    int value_total = 0;
    int i = 0;
    int j = 0;
    for (i = 0; i <=COUNT; i++) {
    		value1 = rand() % (MAX + 1);
    		value2 = rand() % (MAX + 1);
    		p1 = buf_1 + value1*1024;
    		p2 = buf_2 + value2*1024;
    		for (j = 0; j < 1024; j++) {
    				value_total += p1[j];
    				value_total += p2[j];
    		}
    }
    return NULL;
}


int main(void)
{
	
		buf_1 = (char *)calloc(1, BUF_SIZE);
		buf_2 = (char *)calloc(1, BUF_SIZE);
		memset(buf_1, 0, BUF_SIZE);
		memset(buf_2, 0, BUF_SIZE);
		
    pthread_t th_a, th_b;
    void *retval;
    pthread_create(&th_a, NULL, pth_1, 0);
    pthread_create(&th_b, NULL, pth_2, 0);

    pthread_join(th_a, &retval);
    pthread_join(th_b, &retval);
    return 0;
}

我的實驗機器上,偶數cpu在node 0 上,奇數cpu在node 1上,vm有2個cpu,程序有2個線程,分別將vm綁定到8,9和10,12,通過time命令運行程序,time ./test,測試結果如下
8,9
real	1m53.999s
user	3m34.377s
sys	0m3.020s

10,12
real	1m25.706s
user	2m49.497s
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,介紹的很詳細,簡單理解就是可以將host機內容相同的內存合併,節省內存的使用,特別是當vm操作系統都一樣的情況,肯定會有很多內容相同的內存,開啓了KSM,則會將這些內存合併爲一個,當然這個過程會有性能損耗,所以開啓與否,需要考慮使用場景,如果不注重vm性能,而注重host內存使用率,可以考慮開啓,反之則關閉,在/etc/init.d/下,會有兩個服務,服務名稱爲ksm和ksmtuned,都需要關閉。


磁盤

磁盤的優化包括:virtio-blk、緩存模式、aio、塊設備io調度器

virtio

半虛擬化io設備,針對cpu和內存,kvm全是全虛擬化設備,而針對磁盤和網絡,則出現了半虛擬化io設備,目的是標準化guest和host之間數據交換接口,減少交互流程和內存拷貝,提升vm io效率,可以在libvirt xml中設置,disk中加入<target dev='vda' bus='virtio'/>

緩存模式

從vm寫磁盤,有3個緩衝區,guest fs page cache、Brk Driver writeback cache(qemu的cache)、Host FS page cache,在host上的設置,無法改變guest fs page cache,但是可以改變後面2個cache,緩存模式有如下5種,當採用Host FS page cache,會有一個寫同步,會實時將host cache中的數據flush到磁盤上,當然這樣做比較安全,不會丟失數據,但寫性能會受到影響。具體模式見下圖。

第1和第5種,都太極端了,很少會有人使用,常使用的是中間3種,其性能比較如下:


可以看出writeback mode在mail server這種小文件 高io的服務器上,其性能是很差的,none模式大部分情況要比writethrough性能稍好一點,所以選擇none。

啓用方式在libvirt xml disk中加入<driver name='qemu' type='qcow2' cache='none'/>

aio

異步讀寫,分別包括Native aio: kernel AIO 和 threaded aio: user space AIO emulated by posix thread workers,內核方式要比用戶態的方式性能稍好一點,所以一般情況都選擇native,開啓方式<driver name='qemu' type='qcow2' cache='none' aio='native'/>

塊設備調度器

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

deadline:per-device IO queue,較好實時性,較好aggregate throughput,不夠公平,當某些vm有大量io操作,佔用了大量io資源時,其它後加入的vm很有可能搶佔不到io資源。

這個目前筆者還沒有做過測試,但是查看網易和美團雲的方案,都將其設置爲cfq。

開啓方式:echo cfq > /sys/block/sdb/queue/scheduler


網絡

優化項包括virtio、vhost、macvtap、vepa、SRIOV 網卡,下面有幾篇文章寫的非常好

  1. https://www.redhat.com/summit/2011/presentations/summit/decoding_the_code/wednesday/wagner_w_420_kvm_performance_improvements_and_optimizations.pdf
  2. https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html-single/Virtualization_Tuning_and_Optimization_Guide/index.html#chap-Virtualization_Tuning_Optimization_Guide-Networking
  3. http://www.openstack.cn/p2118.html
  4. http://www.ibm.com/developerworks/cn/linux/1312_xiawc_linuxvirtnet/
  5. http://xiaoli110.blog.51cto.com/1724/1558984

virtio

更改虛擬網卡的類型,由全虛擬化網卡e1000rtl8139,轉變成半虛擬化網卡virtiovirtio需要qemuvm內核virtio驅動的支持,這個原理和磁盤virtio原理一樣,不再贅述。

vhost_net

vhost_netvirtiobackend處理程序由user space轉入kernel space,將減少兩個空間內存拷貝和cpu的切換,降低延時和提高cpu使用率

macvtap

代替傳統的tap+bridge,有4中模式,bridge、vepa、private、passthrough
1, Bridge, 完成與 Bridge 設備類似功能,數據可以在屬於同一個母設備的子設備間交換轉發. 當前的Linux實現有一個缺陷,此模式下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網卡, 內核的macvtap數據處理邏輯被跳過,硬件決定數據如何處理,從而釋放了Host CPU資源。MACVTAP Passthrough 概念與PCI Passthrough概念不同,PCI Passthrough針對的是任意PCI設備,不一定是網絡設備,目的是讓Guest OS直接使用Host上的 PCI 硬件以提高效率。MACVTAP Passthrough僅僅針對 MACVTAP網絡設備,目的是饒過內核裏MACVTAP的部分軟件處理過程,轉而交給硬件處理。綜上所述,對於一個 SRIOV 網絡設備,可以用兩種模式使用它:MACVTAP Passthrough 與 PCI Passthrough

PCI pass-through

直通,設備獨享。

SO-IOV

優點是虛擬網卡的工作由host cpu交給了物理網卡來實現,降低了host cpu的使用率,缺點是,需要網卡、主板、hypervisor的支持。

這幾種優化方案,其關係可由下面這張圖來表示。

測試結果,在實驗室2臺host,分別起1臺vm(vm1、vm2),用iperf測試vm1和vm2之間的吞吐量,用ping測試2者之間的響應時間,host機爲百兆網卡,結果如下表所示,可以看出隨着優化的深入,其吞吐量和響應時間都有所改善,由於暫時沒有硬件的支持,macvtap vepa和SR-IOV沒有得到測試。

Test item

Iperf(ping)

rtl8139

87Mb/s(1.239ms)

virtio

89Mb/s(1.140ms)

Virtio + host_net

92Mb/s(1.014ms)

Macvtap(bridge) + virtio + host_net

94Mb/s(0.989ms)

host

95Mb/s(0.698ms)


總結來看網絡虛擬化具有三個層次:

1, 0成本,通過純軟件virtio、vhost、macvtap提升網絡性能;
2, 也可以用非常低的成本按照802.1Qbg中的VEPA模型創建升級版的虛擬網絡,引出虛擬機網絡流量,減少Host cpu負載,但需要物理交換機的配合;
3, 如果網絡性能還是達不到要求,可以嘗試SR-IOV技術,不過需要SR-IOV網卡的支持。


總結:文章總共闡述了cpu、內存、磁盤、網絡的性能優化方案,大部分都是通過kvm參數和系統內核參數的修改來實現。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章