虛擬化概述
將底層的計算機資源虛擬成多組彼此之間互相隔離的計算平台,並且每一個計算平台都應該有五大部件的所有設備(運算器,控制器,存儲器,IO設備)。
虛擬化技術的分類
模擬:硬件+操作系統+模擬器軟件,虛擬機的cpu架構和物理cpu的架構可以不一致。(模擬器模擬出來的CPU指令集和底層物理CPU的指令集不同,就需要虛擬機監視器將模擬的CPU指令集轉化為真正物理CPU的指令集,這個過程需要軟件參與而且性能差)
常用的模擬又:PearPC, Bochs, QEMU
完全虛擬化:虛擬CPU和物理CPU的架構完全相同。(虛擬CPU和物理CPU的架構完全相同,對虛擬機而言只要不是調用到特權指令或敏感指令,普通指令就能直接在底層物理CPU上執行,無需進行轉化。如果虛擬機調用到特權指令,特權指令由虛擬機監視器捕獲后進行翻譯后轉化成宿主機的指令集 或者 虛擬機向虛擬機監視器(VMM)通過調用hypersor call的方式來實現,這取決於是完全虛擬化還是半虛擬化。完全虛擬化可以借助於HVM技術省略指令轉換的過程)
常見的完全虛擬化有:VMware Workstation, VMware Server, Parallels Desktop, KVM, Xen
半虛擬化:para-virtualization
在硬件之上運行hypervisor,hypervisor將底層功能通過hypervisor call向上輸出,要開發能夠運行在hypervisor上的操作系統時,內核需要調用hypervisor call進行開發(稱為API),運行時也需要調用hypervisor call運行(稱為ABI)。所以各個虛擬機的內核是經過修改的,這樣虛擬機自身就知道自身是運行在虛擬化環境中。所以在半虛擬化環境中需要修改guest os的內核。(通常IO半虛擬化無需修改內核,只需安裝特定驅動即可。CPU半虛擬化需要修改內核)
常見的半虛擬化有:xen, uml(user-mode linux)。
早期的xen只支持半虛擬化,后面也支持完全虛擬化。kvm一開始設計就是完全虛擬化。所以kvm性能比xen好;半虛擬化需要修改客戶機操作系統內核、完全虛擬化不需要改客戶機操作系統內核。
OS級別的虛擬化:容器級虛擬化
上述的虛擬化方式中的每個虛擬機都有自身獨立的用戶空間和內核空間,而底層對虛擬機管理的方式是通過hypervisor或host上的VMM(虛擬機監視器)實現,創建虛擬機的目的提供用戶空間來提供服務,內核空間無意義,所以操作系統虛擬化就是將虛擬化向下推了一層即在底層硬件之上運行一個內核,在內核運行一個虛擬化管理器,虛擬化管理器上只提供用戶空間,而沒有提供內核空間,每個用戶空間共享使用內核,這樣就實現將用戶空間分隔為多個,彼此間互相隔離。(穩定性低,但是性能好)
常用的容器級虛擬化由:OpenVZ、LXC
庫虛擬化:虛擬出一個程序運行所依賴的庫環境。
wine,實現在linux運行windows程序。
應用程序虛擬化:
jvm
實現虛擬化的兩種實現方式
Type-I:在硬件上沒有安裝操作系統,而是直接安裝hyper,hyper就是一個虛擬化軟件,可以直接控制硬件。
xen, vmware ESX/ESXi
Type-II:在硬件上安裝操作系統,在操作系統上安裝虛擬化軟件,在虛擬化軟件上創建虛擬機。
kvm, vmware workstation, virtualbox
基礎理論
cpu結構:
cpu分割成4個環,環3上運行普通指令,環0上運行特權指令(包括直接操作硬件的指令、操作cpu中與硬件管控相關的寄存器,都必須使用環0中的指令才能運行),環1環2未使用。操作系統在研發時就明確指定了內核空間中的指令在環0上執行,用戶空間中的指令在環3上執行。用戶空間的進程運行時只要不是特權指令直接在cpu上執行;如果是特權指令,該指令由內核捕獲,由內核基於系統調用的方式來幫進程在環0上執行特權執行,執行后再將結果返回給進程。
當一個操作系統啟動后,操作系統本身不執行任何生產任務,真正的生產功能由進程提供,因此操作系統運行時為了能夠協調多任務,操作系統被分割成了兩段用戶空間和內核空間
內核空間:能夠操作硬件,具有特權權限,運行在環0上;
用戶空間:進程運行在用戶空間,運行在環3上;
當用戶空間中的進程要想執行特權指令或使用硬件時,需要通過系統調用來實現。
概念
宿主機:通常稱為vm monotor即虛擬機監控器又稱為hypervisor ,hypervisor直接管理硬件(一般只管理cpu 內存,IO設備不歸hypervisor管理),相當於內核。hypervisor將CPU和內存的使用、分配過程虛擬成hyper call;對內核的調用稱為系統調用;對hypervisor的調用稱為hyper調用。
引入虛擬化后的問題
虛擬機是完整的主機,也由內核空間和用戶空間組成,理論上虛擬機上的內核能夠控制所有資源,這樣也可以影響其它的虛擬機,導致了虛擬機之間可以互相影響,為了避免這種情況的產生,虛擬機上的cpu是通過軟件模擬的,模擬出來的cpu也有環0、環1、環2、環3,同樣內核空間運行在環0上,用戶空間運行在環3上;當虛擬架構和物理架構一致時,虛擬機上用戶空間的進程依然可以直接運行在cpu的環3上,這時只要特權指令由宿主機的虛擬機管理器捕獲,將特權指令進行轉換,轉換后在物理cpu的環0上執行,執行后再將結果返回給虛擬機;如果虛擬架構和物理架構不一樣,虛擬架構(ppc)、物理架構(x86),很顯然虛擬架構用戶空間的指令集和物理架構用戶空間的指令集不同,這時用戶空間的指令也要通過轉化成宿主機的指令集,這樣效率低。
cpu虛擬化:將CPU按時間切割,實現物理CPU資源的分時復用
cpu虛擬化可以通過模擬和虛擬兩種方式實現。
模擬:emulation,物理架構和虛擬機架構可以不一致,通過純軟件方式實現,效率低;模擬通過軟件方式實現cpu時,需要模擬ring0 1 2 3。
虛擬:virtulization,物理架構和虛擬機架構保持一致。
基於二進制翻譯的全虛擬化(full-virtulization):VMM完全虛擬出一個虛擬平台,guest甚至不知道自己是運行在虛擬平台上;
VMM運行在ring 0,Guess OS的內核空間運行在ring 1,Guess OS上的用戶空間運行在ring 3。Guess OS會在ring 1上執行特權指令,這種在非特權級別上執行特權級別的指令會產生異常(trap),VMM可以捕捉到該異常,VMM發現攔截到的是特權指令就會轉化成對虛擬機操作的虛擬化指令進行執行。ring 3上執行的非特權指令不會被VMM攔截,直接在物理CPU上的ring 3上執行。(x86架構存在虛擬化漏洞,在X86架構下存在19條非特權指令能夠影響系統狀態,這19條非特權指令不會被VMM攔截。所以在x86虛擬化架構中需要將這19條非特權指令轉變成對系統無威脅的指令去執行。將19條非特權指令稱為臨界指令,我們將特權指令和臨界指令統稱為敏感指令。在全虛擬化的場景下虛擬機無法感知自身是運行在虛擬化環境中,由VMM對敏感指令做BT即二進制翻譯成對虛擬機操作的虛擬化指令,這種通過BT的方式無需虛擬機通過修改內核的方式來彌補虛擬化漏洞,但是性能低下。)
半虛擬化(para-virtulization)
CPU半虛擬化需要修改guess os的內核,使得guest的內核是明確知道自身是運行在虛擬化環境中的,所以當guest需要運行敏感指令時不是直接調用敏感指令而是通過hypervisor call將指令發送給VMM,因此guest對敏感指令的調用就被簡化成了簡單的對於宿主機VMM中某些敏感指令的請求,這種方式就無需VMM捕獲異常和BT技術,這就使得guest內核和host相交互的過程大大被簡化了。
硬件輔助的全虛擬化:完全虛擬化和半虛擬化適用於物理CPU不支持虛擬化或者在BIOS中沒有打開VT功能的場景(KVM只能運行在硬件輔助虛擬化場景中)
物理CPU支持虛擬化,即在BIOS中打開VT-X功能。CPU工作在兩種模式下:root模式和non-root模式,VMM工作在root模式,guess os工作在non-root模式。root模式有ring 0 1 2 3,VMM運行在ring 0;non-root模式也有ring 0 1 2 3,guess os運行在ring 0。當guess os發送敏感指令時,指令會被CPU的non-root模式進行處理,non-root模式會發現該指令為敏感指令會切換至root模式讓VMM進行翻譯將敏感指令轉化成對相應虛擬機操作的虛擬化指令。其它非特權指令直接在物理CPU的ring 3上直接執行。
模擬和虛擬化的區別:
模擬:虛擬機所有的硬件設備使用軟件來模擬,物理架構和虛擬機架構可以不一致;
虛擬化:底層硬件平台架構與虛擬機的平台架構相同。
CPU虛擬化性能計算
VCPU個數計算:
復用率建議:
內存虛擬化:將內存按空間切割
內存本身就是虛擬化的,每個進程識別到的是線性地址空間,內核是物理地址空間。在簡單的單機場景中,安裝完操作系統后,內核能夠分配使用整段物理內存空間。在虛擬化環境中,通過hyper來管理物理內存,在hyper中內存被分成內存頁后划分給各虛擬機即虛擬機拿到的內存是離散的。
虛擬機上的一個進程訪問某一內存空間中的數據時:
進程運行在虛擬機的cpu上,進程向cpu發出了對某一線性地址空間(稱為GVA)中數據的訪問,cpu會將該地址空間轉給MMU(內存管理單元),MMU根據內核為每一個進程維護的內存映射表找出該線性地址空間對應的虛擬物理地址(稱為GPA),在hyper上還需通過軟件將GPA的調用再次轉換至物理地址(HPA)。經過了兩次虛擬地址的轉換。在轉換時,會將GVA和HPA的對應關系緩存至TLB,當多個虛擬機的操作系統在cpu上切換時會造成混亂,所以每次虛擬機切換時都要清空TLB。所以這種會造成TLB命中底下,為了解決這種問題,在硬件級別使用MMU 虛擬化。
MMU Virtulization:Intel: EPT, Extended Page Table和AMD: NTP, Nested Page Table
實現虛擬內存和物理內存的映射。
當vm中的進程向虛擬cpu調用線性地址空間,MMU將GVA轉化為GPA的同時,MMU虛擬化會自動完成GVA和HPA的轉化(即擁有兩層MMU)。所以在虛擬化技術中,虛擬機中的每一個進程依然是從GVA轉化成GPA;只不過借助於CPU上MMU的虛擬化技術,同時將GPA直接映射成HPA,省略了GPA到HPA的轉化(通過硬件方式),從而提升了虛擬化性能。
問題:上述借助於CPU上MMU的虛擬化技術,提升了虛擬化性能,但是TLB的命中率仍然無法提高,TLB中緩存的仍然是GVA到HPA的映射關系,虛擬機切換時仍然要清空TLB。為了提高TLB的命中率,於是有了TLB虛擬化。
TLB virtulization:tagged TLB
默認TLB中緩存的是GVA到HPA的映射關系,在TLB virtulization技術中增加了一個字段,即虛擬機的標識符。
內存技術:
大內存頁
GPA到HPA的映射關系即內存映射表保存在內存中,為了優化性能會將內存映射表存放在CPU的寄存器中即TLB(頁面緩沖寄存器),但是寄存器是比較小的,所有只能存放部分內存映射表。於是就有命中率的問題。當GPA到HPA的映射關系在TLB中可以查找到的話,則cache命中,性能就好;當GPA到HPA的映射關系在TLB查找不到時就會到內存中查找,性能就不太好(因為CPU到寄存器中查找的速度快於到內存中查找的速度)。為了提高cache的命中率,就修改TLB表,比如將虛擬內存所對應的物理內存從1k變成4k,這樣就能提高cache命中率。
NUMA架構
早先的服務器都是單CPU,性能無法滿足需求,於是就有了多CPU的服務器,如何在一台服務器內放置多個CPU:
1.SMP架構
能夠在一台服務器上放置多個CPU,多個CPU共享內存,但會有內存沖突的問題。
2.MPP架構
多個節點,每個節點可以設置為SMP,也可以設置非SMP。多個節點之間不會共享內存。
3.NUMA架構
多個節點,每個節點擁有一個CPU和自己的內存,多個節點之間可以共享內存。CPU使用內存的時候,如果訪問本節點的內存速度快,跨節點訪問內存速度慢。基於該特點有兩種技術:
1.host NUMA
在宿主機BIOS上啟用MUMA,開啟host NUMA后,宿主機操作系統能夠識別主機內部的NUMA架構。好處是:1.當宿主機創建虛擬機時,優先使用同個node的CPU、內存。2.當宿主機創建虛擬機時,會查看哪個node的CPU、內存資源較空閑,將虛擬機創建在該node上。
2.guest NUMA
在集群中啟用guest NUMA,開啟guest NUMA后,集群集群下的虛擬機能夠識別宿主機內部的NUMA架構,當虛擬機上的應用程序使用內存的時候,優先使用本節點的內存。
主機內存超分配
內存復用技術
內存復用技術和guest NUMA沖突:因為在內存復用中存在內存置換,會將內存中的內存置換到硬盤,guest NUMA技術無法訪問硬盤上的數據。優先使用內存復用技術。
I/O虛擬化(硬件要支持VT-D)
外存:硬盤、光盤、U盤
網絡設備:網卡
顯示設備:VGA: frame buffer機制
鍵盤鼠標:通過模擬實現
ps/2, usb
I/O虛擬化的方式:
全虛擬化IO設備:workstation、kvm、xen
VMM通過軟件(QEMU)模擬出IO設備,VMM捕獲Guess os對物理IO設備的訪問請求,然后將IO請求轉化成對底層硬件設備的操作;
半虛擬化
在完全虛擬化的IO設備的情況下,虛擬機上有內核空間和用戶空間,虛擬機某個程序要向發送一個網路包,程序無法直接和網卡打交道,程序向內核發起對網卡設備的系統調用,此時內核要通過驅動程序驅動網卡設備,這個網卡設備由軟件模擬的,所以驅動后的結果依然不是能夠向外發送報文的網卡設備,所以這個模擬的網絡設備還要轉化為對hyper的調用,最終轉化為在hyper上的一個軟件模擬網卡設備,在hyper上虛擬網卡可能存在多個,但是物理網卡只能存在有限個,所以hyper上的虛擬網卡要想向外發送網絡報文都要轉化成真正的物理網卡向外發送網絡報文,IO路徑長,性能差。
在以上的過程中在左邊的驅動過程是沒有意義的。在半虛擬化中虛擬機內核明確知道自身的網卡設備是虛擬的,所以就不會在本地通過驅動的方式調用該虛擬設備,而是在本地通過前端驅動的方式即對虛擬設備的調用直接轉換到后端去,減少了IO路徑,提高性能。如下圖:
IO半虛擬化通常由virtio實現,分成兩段,virtio架構如下圖:
前端驅動:virtio前半段,virtio前半段在虛擬機實例中即創建虛擬機時內核已經加載了這些驅動模塊,virtio前半段主要由virtio-blk,virtio-net,virtio-pci,virtio-balloon,virtio-console驅動組成。在CentOS 4.8+,5.3+,6.0+,7.0+內核中都直接支持前端驅動;windows系統中需要安裝專用的程序才能實現;
virtio-balloon:讓kvm中運行的GuestOS動態調整其內存大小
啟用方式:
#qemu-kvm -balloon virtio
手動查看GuestOS的內存用量:
#info balloon
#balloon N
virtio-net:實現網絡半虛擬化
其依賴於GuestOS中的前端驅動,及Qemu中的后端驅動
前端驅動:virtio_net.ko
后端驅動:qemu-kvm -net nic,model=?
啟用方式:
#qemu-kvm -net nic,model=virtio
vhost-net:用於取代工作於用戶空間的qemu中為virtio-net實現的后端驅動以實現性能提升的驅動(后端處理程序在qemu中實現即后端驅動是依賴qemu軟件模擬實現,使用
vhost-net驅動可以提升性能)
#qemu-kvm -net tap,vnet_hdr=on,vhost=on
virtio-blk:實現塊設備半虛擬化
其依賴於GuestOS中的前端驅動,及Qemu中的后端驅動。
啟用方式“
-drive file=/path/to/some_image_file,if=virtio
virtio:虛擬隊列。所有虛擬機的io請求都將發往該隊列,相應的后端處理程序從隊列中取出請求並響應請求;
transport:傳輸層,即將前端驅動發來的任何隊列由transport發往后端處理程序;
后端驅動(virtio backend drivers):后端驅動在qemu中實現即后端驅動是依賴qemu軟件模擬實現,后端處理程序驅動相應的物理設備處理請求。
IO-through: IO透傳,需要硬件支持VFIO(實現USB,PCI and SCSI passthrough)
讓虛擬機直接使用物理設備(需要在虛擬機上安裝對應硬件的驅動程序)。仍然需要hyper去協調,可以接近於硬件性能。但是無法實現虛擬機遷移,雖然性能提升明顯,但是應用范圍不大。
IO虛擬化總結:
完全虛擬化場景中,虛擬機對IO的請求被VMM捕獲,由VMM分時的調用底層硬件資源;半虛擬化場景中,虛擬機對IO的請求發給后端驅動,由后端驅動直接調用底層硬件資源;硬件輔助虛擬化場景中,虛擬機對IO的請求直接調用底層硬件資源。
總結:
完全虛擬化和半虛擬化的區別是:虛擬機是否要協助VMM完成虛擬機所需要的虛擬化環境。虛擬機無感知,即無需修改guest os內核,就是完全虛擬化;讓虛擬機感知自身運行在虛擬化環境中,就要修改guest os內核,就是半虛擬化。注意:kvm只要完全虛擬化和硬件輔助虛擬化,沒有半虛擬化。