1. 程式人生 > >KVM 介紹(2):CPU 和記憶體虛擬化

KVM 介紹(2):CPU 和記憶體虛擬化

學習 KVM 的系列文章: 

1. 為什麼需要 CPU 虛擬化

X86 作業系統是設計在直接執行在裸硬體裝置上的,因此它們自動認為它們完全佔有計算機硬體。x86 架構提供四個特權級別給作業系統和應用程式來訪問硬體。 Ring 是指 CPU 的執行級別,Ring 0是最高級別,Ring1次之,Ring2更次之…… 就 Linux+x86 來說, 
  • 作業系統(核心)需要直接訪問硬體和記憶體,因此它的程式碼需要執行在最高執行級別  Ring0上,這樣它可以使用特權指令,控制中斷、修改頁表、訪問裝置等等。 
  • 應用程式的程式碼執行在最低執行級別上ring3上,不能做受控操作。如果要做,比如要訪問磁碟,寫檔案,那就要通過執行系統呼叫(函式),執行系統呼叫的時候,CPU的執行級別會發生從ring3到ring0的切換,並跳轉到系統呼叫對應的核心程式碼位置執行,這樣核心就為你完成了裝置訪問,完成之後再從ring0返回ring3。這個過程也稱作使用者態和核心態的切換。
  那麼,虛擬化在這裡就遇到了一個難題,因為宿主作業系統是工作在 ring0 的,客戶作業系統就不能也在 ring0 了,但是它不知道這一點,以前執行什麼指令,現在還是執行什麼指令,但是沒有執行許可權是會出錯的。所以這時候虛擬機器管理程式(VMM)需要避免這件事情發生。 虛機怎麼通過 VMM 實現 Guest CPU 對硬體的訪問,根據其原理不同有三種實現技術: 1. 全虛擬化 2. 半虛擬化 3. 硬體輔助的虛擬化

1.1 基於二進位制翻譯的全虛擬化(Full Virtualization with Binary Translation)

客戶作業系統執行在 Ring 1,它在執行特權指令時,會觸發異常(CPU的機制,沒許可權的指令會觸發異常),然後 VMM 捕獲這個異常,在異常裡面做翻譯,模擬,最後返回到客戶作業系統內,客戶作業系統認為自己的特權指令工作正常,繼續執行。但是這個效能損耗,就非常的大,簡單的一條指令,執行完,了事,現在卻要通過複雜的異常處理過程。 異常 “捕獲(trap)-翻譯(handle)-模擬(emulate)” 過程:

1.2. 超虛擬化(或者半虛擬化/作業系統輔助虛擬化 Paravirtualization) 

  半虛擬化的思想就是,修改作業系統核心,替換掉不能虛擬化的指令,通過超級呼叫(hypercall)直接和底層的虛擬化層hypervisor來通訊,hypervisor 同時也提供了超級呼叫介面來滿足其他關鍵核心操作,比如記憶體管理、中斷和時間保持。   這種做法省去了全虛擬化中的捕獲和模擬,大大提高了效率。所以像XEN這種半虛擬化技術,客戶機作業系統都是有一個專門的定製核心版本,和x86、mips、arm這些核心版本等價。這樣以來,就不會有捕獲異常、翻譯、模擬的過程了,效能損耗非常低。這就是XEN這種半虛擬化架構的優勢。這也是為什麼XEN只支援虛擬化Linux,無法虛擬化windows原因,微軟不改程式碼啊。

1.3. 硬體輔助的全虛擬化 

    2005年後,CPU廠商Intel 和 AMD 開始支援虛擬化了。 Intel 引入了 Intel-VT (Virtualization Technology)技術。 這種 CPU,有 VMX root operation 和 VMX non-root operation兩種模式,兩種模式都支援Ring 0 ~ Ring 3 共 4 個執行級別。這樣,VMM 可以執行在 VMX root operation模式下,客戶 OS 執行在VMX non-root operation模式下。   而且兩種操作模式可以互相轉換。執行在 VMX root operation 模式下的 VMM 通過顯式呼叫 VMLAUNCH 或 VMRESUME 指令切換到 VMX non-root operation 模式,硬體自動載入 Guest OS 的上下文,於是 Guest OS 獲得執行,這種轉換稱為 VM entry。Guest OS 執行過程中遇到需要 VMM 處理的事件,例如外部中斷或缺頁異常,或者主動呼叫 VMCALL 指令呼叫 VMM 的服務的時候(與系統呼叫類似),硬體自動掛起 Guest OS,切換到 VMX root operation 模式,恢復 VMM 的執行,這種轉換稱為 VM exit。VMX root operation 模式下軟體的行為與在沒有 VT-x 技術的處理器上的行為基本一致;而VMX non-root operation 模式則有很大不同,最主要的區別是此時執行某些指令或遇到某些事件時,發生 VM exit。 也就說,硬體這層就做了些區分,這樣全虛擬化下,那些靠“捕獲異常-翻譯-模擬”的實現就不需要了。而且CPU廠商,支援虛擬化的力度越來越大,靠硬體輔助的全虛擬化技術的效能逐漸逼近半虛擬化,再加上全虛擬化不需要修改客戶作業系統這一優勢,全虛擬化技術應該是未來的發展趨勢。
利用二進位制翻譯的全虛擬化 硬體輔助虛擬化 作業系統協助/半虛擬化
實現技術 BT和直接執行 遇到特權指令轉到root模式執行 Hypercall
客戶作業系統修改/相容性 無需修改客戶作業系統,最佳相容性 無需修改客戶作業系統,最佳相容性 客戶作業系統需要修改來支援hypercall,因此它不能執行在物理硬體本身或其他的hypervisor上,相容性差,不支援Windows
效能 全虛擬化下,CPU需要在兩種模式之間切換,帶來效能開銷;但是,其效能在逐漸逼近半虛擬化。 好。半虛擬化下CPU效能開銷幾乎為0,虛機的效能接近於物理機。
應用廠商 VMware Workstation/QEMU/Virtual PC VMware ESXi/Microsoft Hyper-V/Xen 3.0/KVM Xen

2. KVM CPU 虛擬化

KVM 是基於CPU 輔助的全虛擬化方案,它需要CPU虛擬化特性的支援。

2.1. CPU 物理特性

這個命令檢視主機上的CPU 物理情況:

複製程式碼
[[email protected] ~]$ numactl --hardware
available: 2 nodes (0-1) //2顆CPU
node 0 cpus: 0 1 2 3 4 5 12 13 14 15 16 17 //這顆 CPU 有8個核心
node 0 size: 12276 MB
node 0 free: 7060 MB
node 1 cpus: 6 7 8 9 10 11 18 19 20 21 22 23
node 1 size: 8192 MB
node 1 free: 6773 MB
node distances:
node   0   1 
  0:  10  21 
  1:  21  10 
複製程式碼

要支援 KVM, Intel CPU 的 vmx 或者 AMD CPU 的 svm 擴充套件必須生效了:

[[email protected] s1]# egrep "(vmx|svm)" /proc/cpuinfo
flags        : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 popcnt aes lahf_lm arat epb dts tpr_shadow vnmi flexpriority ept vpid

2.2 多 CPU 伺服器架構:SMP,NMP,NUMA

從系統架構來看,目前的商用伺服器大體可以分為三類:

  • 多處理器結構 (SMP : Symmetric Multi-Processor):所有的CPU共享全部資源,如匯流排,記憶體和I/O系統等,作業系統或管理資料庫的複本只有一個,這種系統有一個最大的特點就是共享所有資源。多個CPU之間沒有區別,平等地訪問記憶體、外設、一個作業系統。SMP 伺服器的主要問題,那就是它的擴充套件能力非常有限。實驗證明, SMP 伺服器 CPU 利用率最好的情況是 2 至 4 個 CPU 。
  • 海量並行處理結構 (MPP : Massive Parallel Processing) :NUMA 伺服器的基本特徵是具有多個 CPU 模組,每個 CPU 模組由多個 CPU( 如 4 個 ) 組成,並且具有獨立的本地記憶體、 I/O 槽口等。在一個物理伺服器內可以支援上百個 CPU 。但 NUMA 技術同樣有一定缺陷,由於訪問遠地記憶體的延時遠遠超過本地記憶體,因此當 CPU 數量增加時,系統性能無法線性增加。
  • MPP 模式則是一種分散式儲存器模式,能夠將更多的處理器納入一個系統的儲存器。一個分散式儲存器模式具有多個節點,每個節點都有自己的儲存器,可以配置為SMP模式,也可以配置為非SMP模式。單個的節點相互連線起來就形成了一個總系統。MPP可以近似理解成一個SMP的橫向擴充套件叢集,MPP一般要依靠軟體實現。
  • 非一致儲存訪問結構 (NUMA : Non-Uniform Memory Access):它由多個 SMP 伺服器通過一定的節點網際網路絡進行連線,協同工作,完成相同的任務,從使用者的角度來看是一個伺服器系統。其基本特徵是由多個 SMP 伺服器 ( 每個 SMP 伺服器稱節點 ) 通過節點網際網路絡連線而成,每個節點只訪問自己的本地資源 ( 記憶體、儲存等 ) ,是一種完全無共享 (Share Nothing) 結構。

檢視你的伺服器的 CPU 架構:

[[email protected] s1]# uname -a
Linux rh65 2.6.32-431.el6.x86_64 #1 SMP Sun Nov 10 22:19:54 EST 2013 x86_64 x86_64 x86_64 GNU/Linux #這伺服器是 SMP 架構

2.2 KVM CPU 虛擬化

2.2.1 KVM 虛機的建立過程

可見:

(1)qemu-kvm 通過對 /dev/kvm 的 一系列 ICOTL 命令控制虛機,比如

複製程式碼
open("/dev/kvm", O_RDWR|O_LARGEFILE)    = 3
ioctl(3, KVM_GET_API_VERSION, 0)        = 12
ioctl(3, KVM_CHECK_EXTENSION, 0x19)     = 0
ioctl(3, KVM_CREATE_VM, 0)              = 4
ioctl(3, KVM_CHECK_EXTENSION, 0x4)      = 1
ioctl(3, KVM_CHECK_EXTENSION, 0x4)      = 1
ioctl(4, KVM_SET_TSS_ADDR, 0xfffbd000)  = 0
ioctl(3, KVM_CHECK_EXTENSION, 0x25)     = 0
ioctl(3, KVM_CHECK_EXTENSION, 0xb)      = 1
ioctl(4, KVM_CREATE_PIT, 0xb)           = 0
ioctl(3, KVM_CHECK_EXTENSION, 0xf)      = 2
ioctl(3, KVM_CHECK_EXTENSION, 0x3)      = 1
ioctl(3, KVM_CHECK_EXTENSION, 0)        = 1
ioctl(4, KVM_CREATE_IRQCHIP, 0)         = 0
ioctl(3, KVM_CHECK_EXTENSION, 0x1a)     = 0
複製程式碼

(2)一個 KVM 虛機即一個 Linux qemu-kvm 程序,與其他 Linux 程序一樣被Linux 程序排程器排程。

(3)KVM 虛機包括虛擬記憶體、虛擬CPU和虛機 I/O裝置,其中,記憶體和 CPU 的虛擬化由 KVM 核心模組負責實現,I/O 裝置的虛擬化由 QEMU 負責實現。

(3)KVM戶機系統的記憶體是 qumu-kvm 程序的地址空間的一部分。

(4)KVM 虛機的 vCPU 作為 執行緒執行在 qemu-kvm 程序的上下文中。

vCPU、QEMU 程序、LInux 程序排程和物理CPU之間的邏輯關係:

2.2.2 因為 CPU 中的虛擬化功能的支援,並不存在虛擬的 CPU,KVM Guest 程式碼是執行在物理 CPU 之上

    根據上面的 1.3 章節,支援虛擬化的 CPU 中都增加了新的功能。以 Intel VT 技術為例,它增加了兩種執行模式:VMX root 模式和 VMX nonroot 模式。通常來講,主機作業系統和 VMM 執行在 VMX root 模式中,客戶機作業系統及其應用執行在 VMX nonroot 模式中。因為兩個模式都支援所有的 ring,因此,客戶機可以執行在它所需要的 ring 中(OS 執行在 ring 0 中,應用執行在 ring 3 中),VMM 也執行在其需要的 ring 中 (對 KVM 來說,QEMU 執行在 ring 3,KVM 執行在 ring 0)。CPU 在兩種模式之間的切換稱為 VMX 切換。從 root mode 進入 nonroot mode,稱為 VM entry;從 nonroot mode 進入 root mode,稱為 VM exit。可見,CPU 受控制地在兩種模式之間切換,輪流執行 VMM 程式碼和 Guest OS 程式碼。

  對 KVM 虛機來說,執行在 VMX Root Mode 下的 VMM 在需要執行 Guest OS 指令時執行 VMLAUNCH 指令將 CPU 轉換到 VMX non-root mode,開始執行客戶機程式碼,即 VM entry 過程;在 Guest OS 需要退出該 mode 時,CPU 自動切換到 VMX Root mode,即 VM exit 過程。可見,KVM 客戶機程式碼是受 VMM 控制直接執行在物理 CPU 上的。QEMU 只是通過 KVM 控制虛機的程式碼被 CPU 執行,但是它們本身並不執行其程式碼。也就是說,CPU 並沒有真正的被虛級化成虛擬的 CPU 給客戶機使用。

 這篇文章 是關於 vSphere 中 CPU 虛擬化的,我覺得它和 KVM CPU 虛擬化存在很大的一致。下圖是使用 2 socket 2 core 共 4 個 vCPU 的情形:

   幾個概念:socket (顆,CPU 的物理單位),core (核,每個 CPU 中的物理核心),thread (超執行緒,通常來說,一個 CPU core 只提供一個 thread,這時客戶機就只看到一個 CPU;但是,超執行緒技術實現了 CPU 核的虛擬化,一個核被虛擬化出多個邏輯 CPU,可以同時執行多個執行緒)。 

  上圖分三層,他們分別是是VM層,VMKernel層和物理層。對於物理伺服器而言,所有的CPU資源都分配給單獨的作業系統和上面執行的應用。應用將請求先發送給作業系統,然後作業系統排程物理的CPU資源。在虛擬化平臺比如 KVM 中,在VM層和物理層之間加入了VMkernel層,從而允許所有的VM共享物理層的資源。VM上的應用將請求傳送給VM上的作業系統,然後操縱系統排程Virtual CPU資源(作業系統認為Virtual CPU和物理 CPU是一樣的),然後VMkernel層對多個物理CPU Core進行資源排程,從而滿足Virtual CPU的需要。在虛擬化平臺中OS CPU Scheduler和Hyperviisor CPU Scheduler都在各自的領域內進行資源排程。 

   KVM 中,可以指定 socket,core 和 thread 的數目,比如 設定 “-smp 5,sockets=5,cores=1,threads=1”,則 vCPU 的數目為 5*1*1 = 5。客戶機看到的是基於 KVM vCPU 的 CPU 核,而 vCPU 作為 QEMU 執行緒被 Linux 作為普通的執行緒/輕量級程序排程到物理的 CPU 核上。至於你是該使用多 socket 和 多core,這篇文章 有仔細的分析,其結論是在 VMware ESXi 上,效能沒什麼區別,只是某些客戶機作業系統會限制物理 CPU 的數目,這種情況下,可以使用少 socket 多 core。

2.2.3 客戶機系統的程式碼是如何執行的

 一個普通的 Linux 核心有兩種執行模式:核心模式(Kenerl)和使用者模式 (User)。為了支援帶有虛擬化功能的 CPU,KVM 向 Linux 核心增加了第三種模式即客戶機模式(Guest),該模式對應於 CPU 的 VMX non-root mode。

KVM 核心模組作為 User mode 和 Guest mode 之間的橋樑:

  • User mode 中的 QEMU-KVM 會通過 ICOTL 命令來執行虛擬機器
  • KVM 核心模組收到該請求後,它先做一些準備工作,比如將 VCPU 上下文載入到 VMCS (virtual machine control structure)等,然後驅動 CPU 進入 VMX non-root 模式,開始執行客戶機程式碼

三種模式的分工為:

  • Guest 模式:執行客戶機系統非 I/O 程式碼,並在需要的時候驅動 CPU 退出該模式
  • Kernel 模式:負責將 CPU 切換到 Guest mode 執行 Guest OS 程式碼,並在 CPU 退出  Guest mode 時回到 Kenerl 模式
  • User 模式:代表客戶機系統執行 I/O 操作

(來源)

QEMU-KVM 相比原生 QEMU 的改動:

  • 原生的 QEMU 通過指令翻譯實現 CPU 的完全虛擬化,但是修改後的 QEMU-KVM 會呼叫 ICOTL 命令來呼叫 KVM 模組。
  • 原生的 QEMU 是單執行緒實現,QEMU-KVM 是多執行緒實現。

主機 Linux 將一個虛擬視作一個 QEMU 程序,該程序包括下面幾種執行緒:

  • I/O 執行緒用於管理模擬裝置
  • vCPU 執行緒用於執行 Guest 程式碼
  • 其它執行緒,比如處理 event loop,offloaded tasks 等的執行緒

在我的測試環境中(RedHata Linux 作 Hypervisor):

smp 設定的值 執行緒數 執行緒
4 8

1 個主執行緒(I/O 執行緒)、4 個 vCPU 執行緒、3 個其它執行緒

6 10 1 個主執行緒(I/O 執行緒)、6 個 vCPU 執行緒、3 個其它執行緒

這篇文章 談談了這些執行緒的情況。

(來源)

客戶機程式碼執行(客戶機執行緒) I/O 執行緒 非 I/O 執行緒
虛擬CPU(主機 QEMU 執行緒) QEMU I/O 執行緒 QEMU vCPU 執行緒
物理 CPU 物理 CPU 的 VMX non-root 模式中 物理 CPU 的 VMX non-root 模式中

2.2.4 從客戶機執行緒到物理 CPU 的兩次排程

要將客戶機內的執行緒排程到某個物理 CPU,需要經歷兩個過程:

  1. 客戶機執行緒排程到客戶機物理CPU 即 KVM vCPU,該排程由客戶機作業系統負責,每個客戶機作業系統的實現方式不同。在 KVM 上,vCPU 在客戶機系統看起來就像是物理 CPU,因此其排程方法也沒有什麼不同。
  2. vCPU 執行緒排程到物理 CPU 即主機物理 CPU,該排程由 Hypervisor 即 Linux 負責。

    KVM 使用標準的 Linux 程序排程方法來排程 vCPU 程序。Linux 系統中,執行緒和程序的區別是 程序有獨立的核心空間,執行緒是程式碼的執行單位,也就是排程的基本單位。Linux 中,執行緒是就是輕量級的程序,也就是共享了部分資源(地址空間、檔案控制代碼、訊號量等等)的程序,所以執行緒也按照程序的排程方式來進行排程。

(1)Linux 程序排程原理可以參考 這篇文章 和 這篇文章。通常情況下,在SMP系統中,Linux核心的程序排程器根據自有的排程策略將系統中的一個可執行(runable)程序排程到某個CPU上執行。下面是 Linux 程序的狀態機:

(2)處理器親和性:可以設定 vCPU 在指定的物理 CPU 上執行,具體可以參考這篇文章 和 這篇文章

    根據 Linux 程序排程策略,可以看出,在 Linux 主機上執行的 KVM 客戶機 的總 vCPU 數目最好是不要超過物理 CPU 核心數,否則,會出現執行緒間的 CPU 核心資源競爭,導致有虛機因為 vCPU 程序等待而導致速度很慢。

關於這兩次排程,業界有很多的研究,比如上海交大的論文 Schedule Processes, not VCPUs 提出動態地減少 vCPU 的數目即減少第二次排程。

另外,這篇文章 談到的是 vSphere CPU 的排程方式,有空的時候可以研究下並和 KVM vCPU 的排程方式進行比較。

2.3 客戶機CPU結構和模型

KVM 支援 SMP 和 NUMA 多CPU架構的主機和客戶機。對 SMP 型別的客戶機,使用 “-smp”引數:

-smp <n>[,cores=<ncores>][,threads=<nthreads>][,sockets=<nsocks>][,maxcpus=<maxcpus>]

對 NUMA 型別的客戶機,使用 “-numa”引數:

-numa <nodes>[,mem=<size>][,cpus=<cpu[-cpu>]][,nodeid=<node>] 
CPU 模型 (models)定義了哪些主機的 CPU 功能 (features)會被暴露給客戶機作業系統。為了在具有不同 CPU 功能的主機之間做安全的遷移,qemu-kvm 往往不會將主機CPU的所有功能都暴露給客戶機。其原理如下: 你可以執行 qemu-kvm -cpu ? 命令來獲取主機所支援的 CPU 模型列表。 複製程式碼
[[email protected] s1]# kvm -cpu ?
x86       Opteron_G5  AMD Opteron 63xx class CPU                      
x86       Opteron_G4  AMD Opteron 62xx class CPU                      
x86       Opteron_G3  AMD Opteron 23xx (Gen 3 Class Opteron)          
x86       Opteron_G2  AMD Opteron 22xx (Gen 2 Class Opteron)          
x86       Opteron_G1  AMD Opteron 240 (Gen 1 Class Opteron)           
x86          Haswell  Intel Core Processor (Haswell)                  
x86      SandyBridge  Intel Xeon E312xx (Sandy Bridge)                
x86         Westmere  Westmere E56xx/L56xx/X56xx (Nehalem-C)          
x86          Nehalem  Intel Core i7 9xx (Nehalem Class Core i7)       
x86           Penryn  Intel Core 2 Duo P9xxx (Penryn Class Core 2)    
x86           Conroe  Intel Celeron_4x0 (Conroe/Merom Class Core 2)   
x86      cpu64-rhel5  QEMU Virtual CPU version (cpu64-rhel5)          
x86      cpu64-rhel6  QEMU Virtual CPU version (cpu64-rhel6)          
x86             n270  Intel(R) Atom(TM) CPU N270   @ 1.60GHz          
x86           athlon  QEMU Virtual CPU version 0.12.1                 
x86         pentium3                                                  
x86         pentium2                                                  
x86          pentium                                                  
x86              486                                                  
x86          coreduo  Genuine Intel(R) CPU           T2600  @ 2.16GHz 
x86           qemu32  QEMU Virtual CPU version 0.12.1                 
x86            kvm64  Common KVM processor                            
x86         core2duo  Intel(R) Core(TM)2 Duo CPU     T7700  @ 2.40GHz 
x86           phenom  AMD Phenom(tm) 9550 Quad-Core Processor         
x86           qemu64  QEMU Virtual CPU version 0.12.1                 

Recognized CPUID flags:
  f_edx: pbe ia64 tm ht ss sse2 sse fxsr mmx acpi ds clflush pn pse36 pat cmov mca pge mtrr sep apic cx8 mce pae msr tsc pse de vme fpu
  f_ecx: hypervisor rdrand f16c avx osxsave xsave aes tsc-deadline popcnt movbe x2apic sse4.2|sse4_2 sse4.1|sse4_1 dca pcid pdcm xtpr cx16 fma cid ssse3 tm2 est smx vmx ds_cpl monitor dtes64 pclmulqdq|pclmuldq pni|sse3
  extf_edx: 3dnow 3dnowext lm|i64 rdtscp pdpe1gb fxsr_opt|ffxsr fxsr mmx mmxext nx|xd pse36 pat cmov mca pge mtrr syscall apic cx8 mce pae msr tsc pse de vme fpu
  extf_ecx: perfctr_nb perfctr_core topoext tbm nodeid_msr tce fma4 lwp wdt skinit xop ibs osvw 3dnowprefetch misalignsse sse4a abm cr8legacy extapic svm cmp_legacy lahf_lm
[[email protected] s1]# 
複製程式碼

    每個 Hypervisor 都有自己的策略,來定義預設上哪些CPU功能會被暴露給客戶機。至於哪些功能會被暴露給客戶機系統,取決於客戶機的配置。qemu32 和 qemu64 是基本的客戶機 CPU 模型,但是還有其他的模型可以使用。你可以使用 qemu-kvm 命令的 -cpu <model> 引數來指定客戶機的 CPU 模型,還可以附加指定的 CPU 特性。"-cpu" 會將該指定 CPU 模型的所有功能全部暴露給客戶機,即使某些特性在主機的物理CPU上不支援,這時候QEMU/KVM 會模擬這些特性,因此,這時候也許會出現一定的效能下降。 

RedHat Linux 6 上使用預設的 cpu64-rhe16 作為客戶機 CPU model:

你可以指定特定的 CPU model 和 feature:

qemu-kvm -cpu Nehalem,+aes

 

你也可以直接使用 -cpu host,這樣的話會客戶機使用和主機相同的 CPU model。

2.4 客戶機 vCPU 數目的分配方法

  1. 不是客戶機的 vCPU 越多,其效能就越好,因為執行緒切換會耗費大量的時間;應該根據負載需要分配最少的 vCPU。
  2. 主機上的客戶機的 vCPU 總數不應該超過物理 CPU 核心總數。不超過的話,就不存在 CPU 競爭,每個 vCPU 執行緒在一個物理 CPU 核上被執行;超過的話,會出現部分執行緒等待 CPU 以及一個 CPU 核上的執行緒之間的切換,這會有 overhead。
  3. 將負載分為計算負載和 I/O 負載,對計算負載,需要分配較多的 vCPU,甚至考慮 CPU 親和性,將指定的物理 CPU 核分給給這些客戶機。

我們來假設一個主機有 2 個socket,每個 socket 有 4 個core。主頻2.4G MHZ 那麼一共可用的資源是 2*4*2.4G= 19.2G MHZ。假設主機上運行了三個VM,VM1和VM2設定為1socket*1core,VM3設定為1socket*2core。那麼VM1和VM2分別有1個vCPU,而VM3有2個vCPU。假設其他設定為預設設定。

那麼三個VM獲得該主機CPU資源分配如下:VM1:25%; VM2:25%; VM3:50%

 假設執行在VM3上的應用支援多執行緒,那麼該應用可以充分利用到所非配的CPU資源。2vCPU的設定是合適的。假設執行在VM3上的應用不支援多執行緒,該應用根本無法同時使用利用2個vCPU. 與此同時,VMkernal層的CPU Scheduler必須等待物理層中兩個空閒的pCPU,才開始資源調配來滿足2個vCPU的需要。在僅有2vCPU的情況下,對該VM的效能不會有太大負面影響。但如果分配4vCPU或者更多,這種資源排程上的負擔有可能會對該VM上執行的應用有很大負面影響。

確定 vCPU 數目的步驟。假如我們要建立一個VM,以下幾步可以幫助確定合適的vCPU數目

1 瞭解應用並設定初始值

    該應用是否是關鍵應用,是否有Service Level Agreement。一定要對執行在虛擬機器上的應用是否支援多執行緒深入瞭解。諮詢應用的提供商是否支援多執行緒和SMP(Symmetricmulti-processing)。參考該應用在物理伺服器上執行時所需要的CPU個數。如果沒有參照資訊,可設定1vCPU作為初始值,然後密切觀測資源使用情況。

2 觀測資源使用情況

    確定一個時間段,觀測該虛擬機器的資源使用情況。時間段取決於應用的特點和要求,可以是數天,甚至數週。不僅觀測該VM的CPU使用率,而且觀測在作業系統內該應用對CPU的佔用率。特別要區分CPU使用率平均值和CPU使用率峰值。

     假如分配有4個vCPU,如果在該VM上的應用的CPU

  • 使用峰值等於25%, 也就是僅僅能最多使用25%的全部CPU資源,說明該應用是單執行緒的,僅能夠使用一個vCPU (4 * 25% = 1 )
  • 平均值小於38%,而峰值小於45%,考慮減少 vCPU 數目
  • 平均值大於75%,而峰值大於90%,考慮增加 vCPU 數目

3 更改vCPU數目並觀測結果

每次的改動儘量少,如果可能需要4vCPU,先設定2vCPU在觀測效能是否可以接受。

2. KVM 記憶體虛擬化

2.1 記憶體虛擬化的概念

    除了 CPU 虛擬化,另一個關鍵是記憶體虛擬化,通過記憶體虛擬化共享物理系統記憶體,動態分配給虛擬機器。虛擬機器的記憶體虛擬化很象現在的作業系統支援的虛擬記憶體方式,應用程式看到鄰近的記憶體地址空間,這個地址空間無需和下面的物理機器記憶體直接對應,作業系統保持著虛擬頁到物理頁的對映。現在所有的 x86 CPU 都包括了一個稱為記憶體管理的模組MMU(Memory Management Unit)和 TLB(Translation Lookaside Buffer),通過MMU和TLB來優化虛擬記憶體的效能。    KVM 實現客戶機記憶體的方式是,利用mmap系統呼叫,在QEMU主執行緒的虛擬地址空間中申明一段連續的大小的空間用於客戶機實體記憶體對映。 圖片來源 HVA 同下面的 MA,GPA 同下面的 PA,GVA 同下面的 VA) 在有兩個虛機的情況下,情形是這樣的: 可見,KVM 為了在一臺機器上執行多個虛擬機器,需要增加一個新的記憶體虛擬化層,也就是說,必須虛擬 MMU 來支援客戶作業系統,來實現 VA -> PA -> MA 的翻譯。客戶作業系統繼續控制虛擬地址到客戶記憶體實體地址的對映 (VA -> PA),但是客戶作業系統不能直接訪問實際機器記憶體,因此VMM 需要負責對映客戶實體記憶體到實際機器記憶體 (PA -> MA)。 VMM 記憶體虛擬化的實現方式:
  • 軟體方式:通過軟體實現記憶體地址的翻譯,比如 Shadow page table (影子頁表)技術
  • 硬體實現:基於 CPU 的輔助虛擬化功能,比如 AMD 的 NPT 和 Intel 的 EPT 技術
影子頁表技術:

2.2 KVM 記憶體虛擬化

 KVM 中,虛機的實體記憶體即為 qemu-kvm 程序所佔用的記憶體空間。KVM 使用 CPU 輔助的記憶體虛擬化方式。在 Intel 和 AMD 平臺,其記憶體虛擬化的實現方式分別為:
  • AMD 平臺上的 NPT (Nested Page Tables) 技術
  • Intel 平臺上的 EPT (Extended Page Tables)技術

EPT 和 NPT採用類似的原理,都是作為 CPU 中新的一層,用來將客戶機的實體地址翻譯為主機的實體地址。關於 EPT, Intel 官方文件中的技術如下(實在看不懂