虛擬化的發展歷程和實現方式

範桂颶發表於2018-07-11

 前言

  現在市場上最常見的虛擬化軟體有VMWare workstation(VMWare)、VirtualBox(Oracle)、Hyper-V(Microsoft)、KVM(Redhat)、Xen等,這些軟體統稱之為VMM(Virtual Machine Monitor),使用不同的虛擬化實現。而這些虛擬化實現的方式可以分為全虛擬化、半虛擬化、硬體虛擬化等,本篇主要是理解這些虛擬化實現的原理。

 虛擬化

  虛擬化的誕生與實現:

  1961年 — IBM709機實現了分時系統,將CPU佔用切分為多個極短(1/100sec)時間片,每一個時間片都執行著不同的任務。通過對這些時間片的輪詢,這樣就可以將一個CPU虛擬化或者偽裝成為多個CPU,並且讓每一顆虛擬CPU看起來都是在同時執行,這就是虛擬機器的雛形。後來的system360機都支援分時系統。

  1972年 — IBM正式將system370機的分時系統命名為虛擬機器。

  1990年 — IBM推出的system390機支援邏輯分割槽,即將一個cpu分為若干份(最多10份),而且每份cpu都是獨立的,也就是一個物理cpu可以邏輯的分為10個cpu。

  直到IBM將分時系統開源後,個人PC終於臨來了虛擬化的開端,後來才有了上述的虛擬機器軟體的發展。所以至今為止仍然有一部分虛擬機器軟體應用來了分時系統作為虛擬化的基礎實現。

  虛擬化的目的:使用邏輯來表示資源,從而擺脫物理限制的約束。提高物理資源的利用率。

  虛擬化的原理:在OS中加入一個虛擬化層(VMM),虛擬化層可以對下層(HostOS)硬體資源(物理CPU、記憶體、磁碟、網路卡、顯示卡等)進行封裝、隔離,抽象為另一種形式的邏輯資源,再提供給上層(GuestOS)使用。所以你可以理解VMM其實就是聯絡HostOS和GuestOS的一箇中介軟體,當然虛擬化可以將一份資源抽象為多份,也可以將多份資源抽象為一份。

  通過虛擬化技術實現的虛擬機器一般被稱之為GuestOS(客戶),而作為GuestOS載體的物理主機稱之為HostOS(宿主)。

 虛擬機器Virtual Machine

  • 由VMM提供的高效(>80%)、獨立的計算機系統
  • 擁有自己的虛擬硬體(CPU、記憶體、網路裝置、儲存裝置)
  • 對於上層軟體,虛擬機器就是真實的機器
  • Virtual Machine Monitor

  滿足上面幾個條件的OS就是虛擬機器。

  VM的特性

  同質:VM的本質與物理機的本質相同,e.g. CPU的ISA(指令集架構 Instruction Set Architecture)相同

  高效:效能與物理機接近,在VM上執行的大多數指令應該有許可權和能力直接在硬體上執行,只有少數的敏感指令由VMM來處理。

  資源可控:VMM對物理機和虛擬機器的資源都是絕對可控的

  Redhat曾經測試過一些應用服務在虛擬機器上執行的效率。一部分的報告如下:

IBM DB2 SAP ORACLE JAVA LAMP
VM=HOST * 90% VM=HOST * 90% VM=HOST * 90% VM=HOST * 94% VM=HOST * 138%

  NOTE:LAMP在VM上執行的效率之所以能夠提高是因為將Apache、PHP/Python、MySQL 3個應用服務拆分到3個不同的VM中執行。

 虛擬化的分類

  在虛擬化發展的早期主要以全虛擬化和半虛擬化兩大流派為主,兩者各有優缺點。如果能適當的將其應用不同的環境中,就能充分的發揮兩者的特性以獲得更高的收益。隨著這兩大流派的分歧和競爭愈演愈烈,由Intel領銜的硬體廠商也紛紛加入到虛擬化的浪潮中,開啟了(大航海時代)硬體虛擬化的時代,從此全虛擬化和半虛擬化前進的道路逐漸有了靠攏的趨勢。再到後來的 第二代的記憶體虛擬化、第三代的匯流排虛擬化 的出現和興起,當下虛擬化市場已經不再以單純賣賣虛擬化軟體為主要盈利手段,而是將虛擬化技術整合在更大、更完善的虛擬化平臺解決方案中。其中包括Redhat的RHEV、VMWare的vSphere等。

  x86 CPU架構與虛擬化的關係

  在理解各種虛擬化的實現之前,首先需要了解一般x86 CPU的架構。

  注意:CPU為了保證程式程式碼執行的安全性、多使用者的獨立性、保護OS的正常執行,提出了CPU執行狀態的概念。這樣能夠限制不同程式之間的訪問能力,避免一個程式獲取另一個程式的記憶體資料造成資料混亂,同時也避免了程式錯誤的操作物理硬體。一般CPU都會劃分為 使用者態 和 核心態 ,x86的CPU架構更是細分為了Ring3~0四種狀態。

  Ring3 使用者態(User Mode):執行在使用者態的程式程式碼需要受到CPU的檢查,使用者態程式程式碼只能訪問 記憶體頁表項中 規定能被使用者態程式程式碼訪問的頁面虛擬地址(受限的記憶體訪問),而且還只能訪問 TSS中的I/O Permission Bitmap 中規定能被使用者態程式程式碼訪問的埠。甚至不能直接訪問外圍硬體裝置、不能搶佔CPU。所有的應用程式(Application)都執行在使用者態上。——當執行在使用者態的Application需要呼叫只能被核心態程式碼直接訪問的硬體裝置時,CPU會通過特別的介面去呼叫核心態的程式碼,以此來實現Application對硬體裝置的呼叫。 如果使用者態的Application直接呼叫硬體裝置時,就會被Host OS捕捉到並觸發異常,彈出警告視窗。

  Ring0 核心態(Kernel Mode):是Host OS Kernel執行的模式,執行在核心態的程式碼可以無限制的對系統記憶體、裝置驅動程式、網路卡介面、顯示卡介面等外圍硬體裝置進行訪問。只有Host OS能夠無限制的訪問磁碟、鍵盤等外圍硬體裝置的資料,但是首先需要在Host OS上安裝驅動程式。

  虛擬化實現圖:

  粗略而言,GuestOS和VMM都屬於執行在Ring3上的應用程式,GuestOS操作硬體裝置時並執行操作指令時,VMM會將該操作指令監控、捕獲、檢測後將指令傳遞給HostOS,HostOS會將GuestOS發出的執行於使用者態的操作指令模擬為核心態指令。

  注意:當上述的流程是非常簡略的,在與全虛擬化和半虛擬化的實現過程集合時,就會變得非常複雜。

  全虛擬化 Full virtualization

  GuestOS可以直接在全虛擬化VMM上執行而不需要對GuestOS本身的核心程式碼做任何修改,全虛擬化的GuestOS具有完全的物理機特性。既VMM會為GuestOS抽象模擬出它所需要的包括CPU、磁碟、記憶體、網路卡、顯示卡等抽象硬體資源,所以全虛擬化的GuestOS並不會知道自己其實是一臺虛擬機器。

  結合上述的虛擬化實現圖來看:當我們使用GuestOS的時候,不可避免的會呼叫GuestOS中的 虛擬裝置驅動程式 和 核心排程程式 來操作硬體裝置。與HostOS的不同在於,HostOS執行在CPU的核心態中,這就表示HostOS可以直接對硬體裝置進行操作。但GuestOS作為一個執行在CPU使用者態中應用程式,不能夠直接的操作硬體裝置。為了解決這個問題,VMM引用了兩個機制——特權解除 & 陷入模擬。

  特權解除:也稱之為 翻譯,當GuestOS需要呼叫執行在核心態的指令時,VMM就會動態的將核心態指令捕獲並呼叫若干執行在非核心態的指令來模擬出期望得到的效果(GuestOS和VMM是執行在使用者態上的應用程式),從而將核心態的特權解除。解除了核心態的特權後,就能夠在GuestOS中執行大部分的核心態指令了。但是,這仍然不能完美的解決問題。因為在一個OS的指令集中還存在著一種敏感指令(可能是核心態,也可能是使用者態)。此時就需要陷入模擬的實現。

  陷入模擬:無論是HostOS還是GuestOS,只要是一個OS都必然會存在有敏感指令(reboot、shutdown等)。試想如果我們希望將GuestOS重啟,並在GuestOS中執行了reboot指令,但是卻將HostOS給重啟了,這將會非常糟糕。VMM的陷入模擬機制就是為了解決這個問題。e.g. 在GuestOS中執行了敏感指令reboot時,VMM首先會將敏感指令reboot捕獲、檢測並判定其為敏感指令。此時VMM就會陷入模擬,將敏感指令reboot模擬成一個只針對GuestOS進行操作的、非敏感的、並且執行在非核心態上的"reboot"指令,最後CPU執行虛擬機器的重啟操作。

  由於全虛擬化VMM會頻繁的捕獲這些核心態的和敏感的指令,將這些指令進行轉換之後,再交給CPU執行。所以 經過了兩重轉換,導致其效率會比半虛擬化更低,但全虛擬化VMM應用程式的好處在於其不需要對GuestOS的核心原始碼做修改,所以全虛擬化的VMM可以安裝絕大部分的OS(暫時來說只有已Linux、open soralis、BSD等幾種OS開源了核心程式碼)。典型的全虛擬化軟體有 —— VMWare、Hyper-V、KVM-x86(複雜指令集)。

  全虛擬化的兩種實現方式:

  1). 基於二進位制翻譯的全虛擬化

  2). 基於掃描和修補的全虛擬化

  半虛擬化 Paravirtualization

  半虛擬化是需要GuestOS協助的虛擬化。因為在半虛擬化VVMM中執行的GuestOS,都需要將其核心原始碼進行都進過了特別的修改。半虛擬化VMM在處理敏感指令和核心態指令的流程上相對更簡單一些。在半虛擬化VMM上執行的GuestOS都需要修改核心程式碼,主要是修改GuestOS指令集中的敏感指令和核心態指令。讓HostOS在捕抓到沒有經過半虛擬化VMM模擬和翻譯處理的GuestOS核心態指令或敏感指令時,HostOS也能夠準確的判斷出該指令是否屬於GuestOS(GuestOS知道自己是虛擬機器)。這樣就可以高效的避免了上述問題。典型的半虛擬化軟體有——Xen、KVM-PowerPC(簡易指令集)

  半虛擬化除了修改核心外還有另外一種實現方法——在每一個GuestOS中安裝半虛擬化軟體,e.g. VMTools、RHEVTools。

  注意:若使用KVM執行Windows時,一定要安裝半虛擬化驅動Tools,否則無法工作。現在主流的半虛擬化驅動是由IBM和redhat聯合開發一個通用半虛擬機器驅動virtio 。

  硬體輔助虛擬化 HVM

  2005年 — Intel提出並開發了由CPU直接支援的虛擬化技術。這種虛擬化技術引入新的CPU執行模式和新的指令集,使得VMM和GuestOS執行於不同的模式下(VMM=Root Mode;GuestOS=Non-Root Mode),GuestOS執行於受控模式,原來的一些敏感指令在受控模式下會全部陷入VMM,由VMM來實現模擬,這樣就解決了部分非核心態敏感指令的陷入——模擬難題,而且模式切換時上下文的儲存恢復由硬體來完成,這樣就大大提高了陷入——模擬時上下文切換的效率 。該技術的引入使x86 CPU可以很容易地實現完全虛擬化。故皆被幾乎所有之前分歧的各大流派所採用,包括KVM-x86,VMWare ESX Server 3,Xen 3.0 。

  HVM的分類:

  1). Intel –> VT-X

  2). AMD –> AMD-V

  記憶體虛擬化

  原來的GuestOS使用的是虛擬記憶體,不可以缺少虛擬記憶體到實體記憶體的翻譯,影響了虛擬機器的效率。後來Intel EPT AMD RVI表示支援記憶體虛擬化。

  記憶體虛擬化的對映實現*

  A –> 虛擬地址(VA),指GuestOS提供給其應用程式使用的線性地址空間。

  B –> 實體地址(PA),經VMM抽象的,虛擬機器看到的偽實體地址

  C –> 機器地址(MA),真是的機器實體地址,即地址匯流排上出現的地址訊號

  記憶體地址的對映關係::

  GuestOS:PA = f(VA) #GuestOS維護著一套頁表,負責VA到PA的對映

  VMM:MA = g(PA) #VMM維護著一套頁表,負責PA到MA的對映

  通過轉換方法實現了從虛擬地址到機器地址的對映。實際執行時,使用者程式訪問VA1,經過GuestOS的頁錶轉換得到PA1,再由VMM介入並使用VMM的頁表將PA1轉換為MA1 。

  匯流排虛擬化

  分類:

  1). Intel –> VT/d

  2). AMD –> iommu

  匯流排虛擬化可以實現將一塊網路卡分給若干個GuestOS使用,每個虛擬機器1/N,效能高,接近真機。

  從軟體的角度出發,IO裝置就是一堆狀態暫存器,控制暫存器,中斷並與其互動

  主要的虛擬化方式:裝置介面完全模擬、前端-後端模擬(Xen) 

  直接劃分:直接把物理裝置劃分給Guest OS,無須經過VMM。Intel VT-d

  記憶體虛擬化和匯流排虛擬化進一步的拉近了GuestOS和HostOS的執行效能。

相關文章