當前位置:
首頁 > 科技 > 虛擬化技術發展編年史

虛擬化技術發展編年史

作者 | 范桂颶

責編 | 屠敏

出品 | CSDN 博客

前言

我已經想不起來是從什麼時候開始的,突然就對計算機歷史產生了濃厚的興趣。於是我想著,要不以後所有系列文章的開篇都先和大家聊聊歷史吧。其實說來挺有意思,看過去到底是為了看未來,因為歷史總是驚人的相似,幾乎所有的問題都能夠在歷史長河中尋得答案。可惜的是,但凡歷史,最是難寫,筆者礙於能力有限,還望大家多指點一二。

什麼是虛擬化?

在計算機科學中,虛擬化技術(Virtualization)是一種資源管理(優化)技術,將計算機的各種物理資源(e.g. CPU、內存以及磁碟空間、網路適配器等 I/O 設備)予以抽象、轉換,然後呈現出來的一個可供分割並任意組合為一個或多個(虛擬)計算機的配置環境。虛擬化技術打破了計算機內部實體結構間不可切割的障礙,使用戶能夠以比原本更好的配置方式來應用這些計算機硬體資源。而這些資源的虛擬形式將不受現有架設方式,地域或物理配置所限制。虛擬化技術是一個廣義的術語,根據不同的對象類型可以細分為:

平台虛擬化(Platform Virtualization):針對計算機和操作系統的虛擬化。

資源虛擬化(Resource Virtualization):針對特定的系統資源的虛擬化,如內存、存儲、網路資源等。

應用程序虛擬化(Application Virtualization):包括模擬、模擬、解釋技術等,如 Java 虛擬機(JVM)。

這裡我們主要討論的是平台虛擬化。首先提出第一個問題:當我們討論平台虛擬化技術,實際在討論什麼?我認為討論的是 Hypervisor 或稱為 VMM(Virtual Machine Monitor),本篇我們主要回顧 VMM 的發展歷程,並思考之中的原因。

虛擬化技術發展編年史

開篇

1959 年 6 月,牛津大學的計算機教授,克里斯·托弗(Christopher Strachey)在國際信息處理大會(International Conference on Information Processing)上發表了一篇名為《大型高速計算機中的時間共享》(Time Sharing in Large Fast Computer)的學術報告,他在文中首次提出了 「虛擬化」 的基本概念,還論述了什麼是虛擬化技術。這篇文章被認為是最早的虛擬化技術論述,從此拉開了虛擬化發展的帷幕。

克里斯·托弗還同時提出了 Multi-Processing(多道程序)這一超前的概念。Multi-Processing 解決了應用程序因等待外部設備而導致處理器空轉問題,同時也解決了用戶如何調試(Debug)代碼的問題。即便在現在看來,多道程序的理念仍是操作系統在 「並發」 領域中的隗寶。

When I wrote the paper in 1959 I, in common with everyone else, had no idea of the difficulties which would arise in writing the software to control either the time-sharing or multi-programming. If I had I should not have been so enthusiastic about them.

– Christopher Strachey

Christopher Strachey

大型機和小型機的虛擬化

1960 年,為了應對物理學領域的計算需求,美國啟動 Atlas 超級計算機(Super Computer)項目。同期的英國全國只有 16 台計算機,日不落帝國的詛咒在計算機領域也無法倖免。

1961 年,由麻省理工學院的 Fernando Corbato 教授帶領團隊開始研發 CTSS(Compatible Time Sharing System,兼容性分時系統)項目,並由 IBM 提供硬體設備和工程師進行支持。分時系統可以說是硬體虛擬化的根本,CTSS 為後來 IBM 的 TSS 打下了基礎。

1962 年,第一台 Atlas 超級計算機 Atlas 1 誕生,Atlas 1 是第一台實現了虛擬內存(Virtual Memory)概念的計算機,並將其稱為一級存儲(one-level store)。Atlas 1 還是第一個實現了名為 Supervisor 的底層資源管理組件的計算機,Supervisor 可以通過特殊的指令或代碼來管理物理主機的硬體資源。例如:中央處理器的時間分配。

沒錯,操作系統最早的稱謂其實是 Supervisor,往後還被叫過一段時間的 Master Control Program(主控程序),但最終 Operating System 勝出了。此時你或許能夠理解為什麼虛擬機管理程序會被統稱為 Hypervisor(Super、Hyper 是同意詞,意為超級,但詞義上 Hyper 比 Super 還要高級一些)。

1963 年使用打孔機的第一代 Atlas 超級計算機

1960 中期,IBM 在 Thomas J. Watson Research Center (NY) 進行 M44/44X 計算機研究項目。M44/44X 項目基於 IBM 7044(M44)實現了多個具有突破性的虛擬化概念,包括部分硬體共享(partial hardware sharing)、時間共享(time sharing)、內存分頁(memory paging)以及實現了虛擬內存管理的 VMM。通過這些虛擬化技術,應用程序可以運行在這些虛擬的內存之中,實現了在同一台主機上模擬出多個 7044 系統(44X)。M44/44X 項目首次使用了 VM(Virtual Machine) 和 VMM(Virtual Machine Monitor)一詞,被認為是世界上第一個支持虛擬機的系統。

1964 年:IBM 推出了著名的 System/360。你或許有所耳聞,System/360 的開發過程被視為了計算機發展史上最大的一次豪賭,為了研發 System/360,IBM 決定徵召六萬多名新員工,創建了五座新工廠。即便如此,當時的出貨時間仍被不斷順延。吉恩·阿姆達爾是系統主架構師,當時的項目經理佛瑞德·布魯克斯(Frederick P. Brooks, Jr.)事後根據這項計劃的開發經驗,寫出了同樣著名的《人月神話:軟體項目管理之道》(The Mythical Man-Month: Essays on Software Engineering)記述人類工程史上一項里程碑式的大型複雜軟體系統開發經驗。最終,IBM System/360 取得了巨大的商業成功。System/360 不僅提供了新型的操作系統(讓單一操作系統適用於整個系列的產品,這是 System/360 系列大型機成功的關鍵),還實現了基於全硬體虛擬化(Full Hardware Virtualization)的虛擬機解決方案,包括:頁式虛擬內存(4k 分頁虛擬存儲系統),虛擬磁碟以及 TSS 分時系統。System/360 最多可提供 14 個虛擬機,每個虛擬機具有 256k 固定虛擬內存。

這裡有必要著重介紹一下 TSS (Time Sharing System,分時共享系統),它能夠讓一台主機上連接多個帶有顯示器和鍵盤的終端,同時允許多個用戶通過主機的終端,以交互方式使用計算機,共享主機中的資源。分時操作系統本質是一個多用戶互動式操作系統。其中,「分時」 的含義是將 CPU 佔用切分為多個極短(e.g. 1/100sec)的時間片,每個時間片都執行著不同的任務。通過對這些時間片的輪詢,就可以將一個 CPU 「偽裝」(虛擬化)成多個 vCPU,並且讓每顆 vCPU 看起來都是並行運行的。最終達到多個用戶分享使用同一台計算機,多個程序分時共享硬體和軟體資源的效果。TSS 被認為是最原始的虛擬化技術。

可見,最初虛擬化技術的應用和發展源於大型機對分時系統的需求。這種通過硬體的方式來生成多個可以運行獨立操作系統軟體的虛擬機實例,解決了早期大型計算機只能單任務處理而不能分時多任務處理的問題。由於這種虛擬化技術是基於硬體設備來實現的,故被稱為硬體虛擬化(Hardware virtualization)。但需要注意的是,這一說法在後來被進一步細分為了狹義的硬體虛擬化技術,現今更加為人多熟知的硬體虛擬化是指:一種對計算機或操作系統的虛擬化,能夠對用戶隱藏真實的計算機硬體,表現出另一個抽象的計算平台。

System/360

The Mythical Man-Month: Essays on Software Engineering

偉大源自於偉大!

1974 年,Gerald J. Popek(傑拉爾德·J·波佩克)和 Robert P. Goldberg(羅伯特·P·戈德堡)在合作論文《可虛擬第三代架構的規範化條件》(Formal Requirements for Virtualizable Third Generation Architectures)中提出了一組稱為虛擬化準則的充分條件,又稱波佩克與戈德堡虛擬化需求(Popek and Goldberg virtualization requirements)即:虛擬化系統結構的三個基本條件。滿足這些條件的控制程序才可以被稱為虛擬機監控器(Virtual Machine Monitor,簡稱 VMM):

資源控制(Resource Control)。控制程序必須能夠管理所有的系統資源。

等價性(Equivalence)。在控制程序管理下運行的程序(包括操作系統),除時序和資源可用性之外的行為應該與沒有控制程序時的完全一致,且預先編寫的特權指令可以自由地執行。

效率性(Efficiency)。絕大多數的客戶機指令應該由主機硬體直接執行而無需控制程序的參與。

該論文儘管基於簡化的假設,但上述條件仍為評判一個計算機體系結構是否能夠有效支持虛擬化提供了一個便利方法,也為設計可虛擬化計算機架構給出了指導原則。同時,Gerald J. Popek 和 Robert P. Goldberg 還在論文中介紹了兩種 Hypervisor 類型,分別是類型 I 和 類型 II。

類型 II(寄居或託管 Hypervisor):VMM 運行在傳統的操作系統上,就像其他計算機程序那樣運行。

特點:

VMM 作為應用程序運行在主操作系統環境內

運行效率一般較類型 I 低

實現案例:

VMware 5.5 以前版本

Xen 3.0 以前版本

Virtual PC 2004

類型 I(原生或裸機 Hypervisor):這些虛擬機管理程序直接運行在宿主機的硬體上來控制硬體和管理客戶機操作系統。

特點:

需要硬體支持

VMM 作為主操作系統

運行效率高

實現案例:

VMware 5.5 及以後版本

Xen 3.0 及以後版本

Virtual PC 2005

KVM

ps:這裡我特意將類型 I 和 II 的順序調轉,至於為什麼,從實現案例可以看出類型 I 已然是時代的選擇。再一個,老實說我確實為這個事實感到震驚,平台虛擬化的雛形竟然在 1974 年就已經確立了的這個事實。

1979 年,Unix 的第 7 個版本引入了 chroot 機制,意味著第一個 操作系統虛擬化(OS-level virtualization) 誕生了。chroot 是直到現在我們依然在使用的一個系統調用,這個系統調用會讓一個進程把指定的目錄作為根目錄,它的所有文件系統操作都只能在這個指定目錄中進行,本質是一種文件系統層的隔離。

ps:操作系統虛擬化這個說法你或許會感到陌生,但容器(Container)你應該非常熟悉了。

在上世紀 60~80 年代,因為虛擬化技術使得大型機和小型機獲得了空前的成功。並且在相當長的一段時間裡,虛擬化技術只在大型機和小型機上得到了應用,而在 x86 平台上的應用仍然進展緩慢。不過也可以理解,以當時 x86 平台的處理能力,應付一兩個應用程序已然捉襟見肘,還怎麼能夠將資源分給更多的虛擬應用呢?而後隨著 x86 的流行,大型機和小型機在新興的伺服器市場中也逐漸失去了競爭力。

x86 架構的虛擬化

直到上世紀 80~90 年代,Intel 公司(戈登·摩爾)提出了摩爾定律,Windows、Mac 等 PC(Personal Computer)電腦被廣泛使用,Wintel 聯盟勢如破竹,還出現了神一般的 Linux 伺服器操作系統。種種原因,到底是 x86 贏得了時代的青睞,成為了伺服器的行業標準。或許在那時 Intel 就已經開始思考為何 「生態」 這件事情了。

摩爾定律的傳統定義是:半導體晶元上的晶體管密度,平均每 18-24 個月翻一番。

Wintel 聯盟:即微軟與英特爾的合作,自 20 世紀 80 年代以來,Wintel 聯盟就主導著全球 PC 市場。

GNU/Linux:開源上帝。

隨著 x86 伺服器和桌面部署的增長也為企業 IT 基礎架構帶來了新的難題:

基礎架構利用率低

基礎架構成本高

IT 運維成本高

故障切換和災難保護不足

最終用戶桌面的維護成本高昂

而解決這些難題就是新時代賦予虛擬化技術的歷史任務,整個 80~90 年代,虛擬化技術及公司如同雨後春筍般湧現。

1987 年:Insignia Solutions 公司演示了一個稱為 SoftPC 的軟體模擬器,這個模擬器允許用戶在 Unix Workstations 上運行 DOS 應用。當時一個可以運行 Microsoft DOS 的 PC 需要 1,500 美金,而使用 SoftPC 模擬,就可以直接在大型工作站上運行 Microsoft DOS 了。

1989 年,Insignia Solutions 發布了 Mac 版的 SoftPC,使蘋果用戶不僅能運行 DOS,還能運行 Windows 操作系統。

1990 年,Keir Fraser 和 Ian Pratt 創建了 XenServer 的初始代碼工程(項目)。

1997 年,蘋果開發了 Virtual PC,後來又賣給了 Connectix 公司。

1998 年,著名的 x86 模擬模擬器 Bochs 發布。

1999 年,VMware 公司率先推出針對 x86 平台推出了可以流暢運行的商業虛擬化軟體 VMaware Workstation。

2000 年,FreeBSD jail,真正意義上的第一個功能完整的操作系統虛擬化技術。利用這個技術,FreeBSD 的系統管理者,可以創造出幾個小型的軟體系統,這些軟體系統被稱為 jails(監獄,即容器。ps:不禁感慨,取名真的很重要)。

2001 年,VMWare 發布 ESX 和 GSX,是 ESXi 的前身。同年,Fabrice Bellard 也發布了目前最流行的,採用了動態二進位翻譯(Binary Translation)技術的開源虛擬化軟體 QEMU(Quick EMUlator)的第一個版本。

基於二進位翻譯的全虛擬化

此時,虛擬化技術的共同目標就是將 x86 架構轉變為通用的共享硬體基礎架構,使應用程序運行環境在隔離性、移動性和操作系統類型方面都有選擇的空間。首先了解一下 x86 架構的特點。

CPU 為了保證程序代碼執行的安全性,多用戶的獨立性以及保證操作系統的穩定性,提出了 CPU 執行狀態的概念。它有效的限制了不同程序之間的數據訪問能力,避免了非法的內存數據操作,同時也避免了應用程序錯誤操作計算機的物理設備。一般的,CPU 都會劃分為用戶態和內核態,而 x86 CPU 更是細分為了 Ring 0~3 四種執行狀態。

Ring0 核心態(Kernel Mode):是操作系統內核的執行狀態(運行模式),運行在核心態的代碼可以無限制的對系統內存、設備驅動程序、網卡介面、顯卡介面等外部設備進行訪問。

顯然,只有操作系統能夠無限制的訪問內存、磁碟、鼠鍵等外圍硬體設備的數據,因為操作系統就是作為計算機硬體資源管理器而存在的,操作系統就是為了讓多個普通應用程序可以更簡單、安全的運行在同一台計算機上而存在的 「特殊的應用程序」。

Ring3 用戶態(User Mode):運行在用戶態的程序代碼需要受到 CPU 的檢查,用戶態程序代碼只能訪問內存頁表項中規定能被用戶態程序代碼訪問的頁面虛擬地址(受限的內存訪問),而且還只能訪問 I/O Permission Bitmap 中規定的能被用戶態程序代碼訪問的埠,不能直接訪問外圍硬體設備、不能搶佔 CPU。

也很顯然,所有的應用程序都應該運行在用戶態中。當應用程序需要訪問外圍硬體設備時,CPU 會通過特別的介面去調用核心態的代碼,以這種旁路的方式來應用程序對硬體設備的調用。如果用戶態的應用程序直接調用硬體設備的話,就會被操作系統捕捉到並觸發異常,彈出警告窗口。

可見,x86 架構與大型機不同,當時的 x86 體系結構缺乏必要的針對虛擬化的硬體支持,難以直接滿足波佩克與戈德堡的虛擬化需求,所以 x86 架構天然不是一個可虛擬化的架構。x86 架構的 CPU 中有 17 條指令成為了虛擬化最大的障礙,錯誤執行這些指令會導致操作系統顯示警告、終止應用程序甚至完全崩潰。當時 VMware 提出了解決這個問題的思路:在虛擬機生成這些特殊的指令時將它們 「困住」,然後將它們轉換成可虛擬化的安全指令,同時保證其他所有的指令不受到干擾地執行。這樣就產生了一種與主機硬體匹配並保持軟體完全兼容性的高性能虛擬機。這就是 全虛擬化(Full virtualization) 技術誕生的背景 —— 必須使用純軟體實現的方式構造 VMM。VMware 首創了這項技術,一舉穩坐虛擬化龍頭老大。

全虛擬化是指虛擬機模擬了完整的底層硬體,包括處理器、物理內存、時鐘、外設等,使得為原始硬體設計的操作系統或其它系統軟體完全不做任何修改就可以在虛擬機中運行。客戶機操作系統(Guest OS)與真實硬體之間的交互可以看成是通過一個預先規定的硬體介面進行的。全虛擬化 VMM 以完整模擬硬體的方式提供全部介面(同時還必須模擬特權指令的執行過程)。

全虛擬化的工作原理:虛擬機是對真實計算環境的抽象和模擬,VMM 需要為每個虛擬機分配一套數據結構來管理它們狀態,包括 vCPU 的全套寄存器,物理內存的使用情況,虛擬設備的狀態等等。VMM 調度虛擬機時,會將其部分狀態恢復到 Host OS 中。但並非所有的狀態都需要恢復,例如主機 CR3 寄存器中存放的是 VMM 設置的頁表物理地址,而不是 Guest OS 設置的值。pCPU 直接運行 Guest OS 的機器指令時,由於 Guest OS 運行在低特權級別(Ring 1),如果 Guest OS 直接訪問 Host OS 的特權狀態(如寫 GDT 寄存器),就會因為許可權不足導致 pCPU 產生異常,然後將運行權主動交還給 VMM。此外,外部中斷的到來也會影響 VMM 的運行。VMM 可能需要先將該虛擬機的當前狀態寫回到狀態數據結構中,分析虛擬機被掛起的原因,然後代表 Guest OS 執行相應的特權操作。最簡單的情況,如 Guest OS 對 CR3 寄存器的修改,只需要更新虛擬機的狀態數據結構即可。一般而言,大部分情況下,VMM 需要經過複雜的流程才能完成原本簡單的操作。最後 VMM 將運行權還給 Guest OS,Guest OS 從上次被中斷的地方繼續執行,或處理 VMM 「塞」入的虛擬中斷和異常。這種經典的虛擬機運行方式被稱為 Trap-And-Emulate(捕獲-模擬),虛擬機對於 Guest OS 完全透明,Guest OS 不需要任何修改,但是 VMM 的設計會比較複雜,系統整體性能受到明顯的損害。

舉例來說:x86 平台中,操作系統執行切換進程頁表的操作,真實硬體會通過提供一個特權 CR3 寄存器來實現該介面,操作系統只需執行 mov pgtable, %%cr3 彙編指令即可。而全虛擬化 VMM 就必須要完整地模擬該介面執行的全過程。如果硬體(主要是 CPU)不提供虛擬化的特殊支持的話,那麼這個模擬過程將會十分複雜:一般而言,VMM 必須運行在最高優先順序來完全控制宿主機操作系統(Host OS),而 Guest OS 需要降級運行,從而不能執行特權操作。當 Guest OS 執行前面的特權彙編指令時,Host OS 產生異常(General Protection Exception),執行控制權重新從 Guest OS 轉到 VMM 手中。VMM 事先分配一個變數作為影子 CR3 寄存器給 Guest OS,將 pgtable(頁表)代表的 Guest OS 物理地址(Guest Physical Address)填入影子 CR3 寄存器,然後 VMM 還需要 pgtable 翻譯成主機物理地址(Host Physical Address)並填入物理 CR3 寄存器,最後返回到 Guest OS中。隨後 VMM 還將處理複雜的 Guest OS 缺頁異常(Page Fault)。

簡單來說就是全虛擬化需要在 VMM 中模擬出一顆包含了控制單元、運算單元、存儲單元、IS(指令集)的 CPU;此外,還需要模擬一張進行虛擬存儲地址和物理存儲地址轉換的頁表;此外,還需要在 VMM 模擬磁碟設備控制器、網路適配器等等各種 I/O 外設介面。如此依賴,Guest OS 就不知道自己其實是個虛擬機了呀,它收到了欺騙。可以想像得到,全虛擬化這種處理器密集型的虛擬化技術實現是異常困難且低效的。比較著名的全虛擬化 VMM 有 Microsoft Virtual PC、VMware Workstation、Sun Virtual Box、Parallels Desktop for Mac 和 QEMU。QEMU 在今年(2019)對外宣稱可以模擬所有設備,天啊,這簡直是個奇蹟般的偉大軟體。但基於這樣的前提,全虛擬化 VMM 必須要克服許多難以解決的問題。例如:

確保 VMM 控制所有的系統資源:x86 處理器有 4 個特權級別,Ring 0 ~ Ring 3,只有運行在 Ring 0 ~ 2 時,處理器才可以訪問特權資源或執行特權指令;運行在 Ring 0 級時,處理器可以訪問所有的特權狀態。x86 平台上的操作系統一般只使用 Ring 0 和 Ring 3 這兩個級別,操作系統運行在 Ring 0 級,用戶進程運行在 Ring 3 級。為了滿足 資源控制(Resource Control) 虛擬化需求條件,VMM 就必須運行在 Ring 0 級,同時為了避免 Guest OS 控制系統資源,Guest OS 不得不降低自身的運行級別,運行在 Ring 1 或 Ring 3 級(Ring 2 不使用)。

特權級壓縮(Ring Compression):VMM 使用分頁或段限制的方式來保護物理內存的訪問,但是 64 位模式下段限制不起作用,而分頁又不區分 Ring 0, 1, 2。為了統一和簡化 VMM的設計,Guest OS 只能和 Guest 進程一樣運行在 Ring 3 級。VMM 必須監視 Guest OS 對 GDT、IDT 等特權資源的設置,防止 Guest OS 運行在 Ring 0級,同時又要保護降級後的 Guest OS 不受 Guest 進程的主動攻擊或無意破壞。

特權級別名(Ring Alias):特權級別名是指 Guest OS 在虛擬機中運行的級別並不是它所期望的。VMM 必須保證 Guest OS 不能獲知正在虛擬機中運行這一事實,否則可能打破 等價性(Equivalence) 虛擬化需求條件。例如,x86 處理器的特權級別存放在 CS 代碼段寄存器內,Guest OS 可以使用非特權 push 指令將 CS 寄存器壓棧,然後 pop 出來檢查該值。又如,Guest OS 在低特權級別時讀取特權寄存器 GDT、LDT、IDT 和 TR,並不發生異常,從而可能發現這些值與自己期望的不一樣。為了解決這個挑戰,VMM 可以使用動態二進位翻譯(Binary Translation)的技術,例如預先把 push %%cs 指令替換,在棧上存放一個影子 CS 寄存器值;又如,可以把讀取 GDT 寄存器的操作 sgdt dest 改為 movl fake_gdt, dest。

地址空間壓縮(Address Space Compression):地址空間壓縮是指 VMM 必須在 Guest OS 的地址空間中保留一部分供其使用。例如,中斷描述表寄存器(IDT Register)中存放的是中斷描述表的線性地址,如果 Guest OS 運行過程中來了外部中斷或觸發處理器異常,必須保證運行權馬上轉移到 VMM 中,因此 VMM 需要將 Guest OS 的一部分線性地址空間映射成自己的中斷描述表的主機物理地址。VMM 可以完全運行在 Guest OS 的地址空間中,也可以擁有獨立的地址空間,後者的話,VMM 只佔用 Guest OS 很少的地址空間,用於存放中斷描述表和全局描述符表(GDT)等重要的特權狀態。無論如何哪種情況,VMM 應該防止 Guest OS 直接讀取和修改這部分地址空間。

處理 Guest OS 的缺頁異常:內存是一種非常重要的系統資源,VMM 必須全權管理,Guest OS 理解的物理地址只是客戶機物理地址(Guest Physical Address),並不是最終的主機物理地址(Host Physical Address)。當 Guest OS 發生缺頁異常時,VMM 需要知道缺頁異常的原因,是 Guest 進程試圖訪問沒有許可權的地址,或是客戶機線性地址(Guest Linear Address)尚未翻譯成客戶機物理地址,還是客戶機物理地址尚未翻譯成主機物理地址。一種可行的解決方法是 VMM 為 Guest OS 的每個進程的頁表構造一個影子頁表(Shadow Page Table),維護 Guest Linear Address 到 Host Physical Address 的映射,主機 CR3 寄存器存放這個影子頁表的物理內存地址。VMM 同時維護一個 Guest OS 全局的 Guest Physical Address 到 Host Physical Address 的映射表。發生缺頁異常的地址總是 Guest Linear Address,VMM 先去 Guest OS 中的頁表檢查原因,如果頁表項已經建立,即對應的 Guest Physical Address 存在,說明尚未建立到 Host Physical Address 的映射,那麼 VMM 分配一頁物理內存,將影子頁表和映射表更新;否則,VMM 返回到 Guest OS,由 Guest OS 自己處理該異常。

處理 Guest OS 中的系統調用(System Call):系統調用是操作系統提供給用戶的服務常式,使用非常頻繁。最新的操作系統一般使用 SYSENTER/SYSEXIT 指令對來實現快速系統調用。SYSENTER 指令通過 IA32_SYSENTER_CS,IA32_SYSENTER_EIP 和 IA32_SYSENTER_ESP 這 3 個 MSR(Model Specific Register)寄存器直接轉到 Ring 0 級;而 SYSEXIT 指令不在 Ring 0 級執行的話將觸發異常。因此,如果 VMM 只能採取 Trap-And-Emulate 的方式處理這 2 條指令的話,整體性能將會受到極大損害。

轉發虛擬的中斷和異常:所有的外部中斷和 pCPU 的異常直接由 VMM 接管,VMM 構造必需的虛擬中斷和異常,然後轉發給 Guest OS。VMM 需要模擬硬體和操作系統對中斷和異常的完整處理流程,例如 VMM 先要在 Guest OS 當前的內核棧上壓入一些信息,然後找到 Guest OS 相應處理常式的地址,並跳轉過去。VMM 必須對不同的 Guest OS 的內部工作流程比較清楚,這增加了 VMM 的實現難度。同時,Guest OS 可能頻繁地屏蔽中斷和啟用中斷,這兩個操作訪問特權寄存器 EFLAGS,必須由 VMM 模擬完成,性能因此會受到損害。Guest OS 重新啟用中斷時,VMM 需要及時地獲知這一情況,並將積累的虛擬中斷轉發。

Guest OS 頻繁訪問特權資源:Guest OS 對特權資源的每次訪問都會觸發 CPU 異常,然後由 VMM 模擬執行,如果訪問過於頻繁,則系統整體性能將會受到極大損害。比如對中斷的屏蔽和啟用,cli(Clear Interrupts)指令在 Pentium 4 處理器上需要花費 60 個時鐘周期(cycle)。又比如,處理器本地高級可編程中斷處理器(Local APIC)上有一個操作系統可修改的任務優先順序寄存器(Task-Priority Register),IO-APIC 將外部中斷轉發到 TPR 值最低的處理器上(期望該處理器正在執行低優先順序的線程),從而優化中斷的處理。TPR 是一個特權寄存器,某些操作系統會頻繁設置(Linux Kernel 只在初始化階段為每個處理器的 TPR 設置相同的值)。

顯然,基於 Trap-And-Emulate 處理方式的全虛擬化雖能夠以純軟體的方式完成虛擬化並解決了許多問題,但同時也帶來了極大的設計複雜性和性能下降。而對於這兩個問題,半虛擬化(Partial virtualization) 想到了一個好辦法:改造 Guest OS,將 Guest OS 原來所有需要被 VMM 截獲、模擬的指令和操作全部改造成與 VMM 協同工作的指令(hypercall)和操作。VMM 不再隱瞞了,因為你(Guest OS)已經知道自己就是個虛擬機了。其核心思想是:動態或靜態地改變 Guest OS 對特權狀態訪問的操作,盡量減少產生不必要的硬體異常,同時簡化 VMM 的設計。

半虛擬化

半虛擬化是一種通過修改 Guest OS 部分訪問特權狀態的代碼以便直接與 VMM 交互的技術。在半虛擬化虛擬機中,部分硬體介面以軟體的形式提供給 Guest OS,這可以通過 Hypercall(VMM 提供給 Guest OS 的直接調用,與系統調用類似)的方式來提供。例如,Guest OS 把切換頁表的代碼修改為調用 Hypercall 來直接完成修改影子 CR3 寄存器和翻譯地址的工作。由於不需要產生額外的異常和模擬部分硬體執行流程,半虛擬化可以大幅度提高性能,比較著名的 VMM 有 Denali、Xen。

2003 年,英國劍橋大學的一位講師發布了開源虛擬化項目 Xen,並成立 XenSource 公司,通過半虛擬化技術為 x86-64 提供虛擬化支持。同年,Intel 正式公布將在 x86 平台的 CPU 上支持虛擬化技術 VT。同年 VMWare 也被 EMC 收購,成為 EMC 迄今最成功的一筆收購。同年,微軟收購 Connectix 公司獲得 Virtual PC 虛擬化技術。

相較於全虛擬化,半虛擬化 VMM 只需要模擬部分底層硬體,因此 Guest OS 不做修改是無法在虛擬機中運行的,甚至運行在虛擬機中的其它程序也需要進行修改,如此代價,換來的就是接近於物理機的虛擬機性能。

有意思的是,半虛擬化其實也很尷尬,對於 Linux 而言自然是改了就改了,但 Windows 你要怎麼改?人家可是閉源的。寫到這裡,不禁會想起自己寫過的代碼,拆東牆補西牆可不值得提倡,要從根源上解決問題。而這個根源自然就是 —— CPU。

既然全虛擬化性能低的主要原因是花費了太多的精力去捕獲 CPU 異常並模擬 CPU 行為,那麼如果 CPU 本身就為 VMM 提供了便利,那豈不是從根本上解決了這個問題?這就是 硬體輔助虛擬化(Hardware-assisted virtualization) 。

基於硬體輔助的全虛擬化

Intel-VT(Intel Virtualization Technology)和 AMD-V 是目前 x86 平台上可用的兩種硬體輔助虛擬化技術。VT-x 為 IA 32 處理器增加了兩種操作模式:VMX root operation 和 VMX non-root operation。VMM 自己運行在 VMX root operation 模式,VMX non-root operation 模式則由 Guest OS 使用。兩種操作模式都支持 Ring 0~3 這 4 個特權級,因此 VMM 和 Guest OS 都可以自由選擇它們所期望的運行級別。這兩種操作模式可以互相轉換。運行在 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。

例如:在上面的例子中,Guest OS 能夠執行修改頁表的彙編指令,再無需 VMM 進行捕獲、模擬。從而減少了相關的性能開銷,也極大簡化了 VMM 設計,進而使 VMM 能夠按通用標準進行編寫,性能更加強大。

又因為 VMM 和 Guest OS 共享底層的處理器資源,所以硬體需要一個物理內存區域來自動保存或恢復彼此執行的上下文。這個區域稱為虛擬機控制塊(VMCS),包括客戶機狀態區(Guest State Area),主機狀態區(Host State Area)和執行控制區。VM entry 時,硬體自動從客戶機狀態區載入 Guest OS 的上下文。並不需要保存 VMM 的上下文,原因與中斷處理程序類似,因為 VMM 如果開始運行,就不會受到 Guest OS的干擾,只有 VMM 將工作徹底處理完畢才可能自行切換到 Guest OS。而 VMM 的下次運行必然是處理一個新的事件,因此每次 VMM entry 時, VMM 都從一個通用事件處理函數開始執行;VM exit 時,硬體自動將 Guest OS 的上下文保存在客戶機狀態區,從主機狀態區中載入 VMM 的通用事件處理函數的地址,VMM 開始執行。而執行控制區存放的則是可以操控 VM entry 和 exit 的標誌位,例如標記哪些事件可以導致 VM exit,VM entry 時準備自動給 Guest OS 「塞」 入哪種中斷等等。

客戶機狀態區和主機狀態區都應該包含部分物理寄存器的信息,例如控制寄存器 CR0,CR3,CR4;ESP 和 EIP(如果處理器支持 64 位擴展,則為 RSP,RIP);CS,SS,DS,ES,FS,GS 等段寄存器及其描述項;TR,GDTR,IDTR 寄存器;IA32_SYSENTER_CS,IA32_SYSENTER_ESP,IA32_SYSENTER_EIP 和 IA32_PERF_GLOBAL_CTRL 等 MSR 寄存器。客戶機狀態區並不包括通用寄存器的內容,VMM 自行決定是否在 VM exit 的時候保存它們,從而提高了系統性能。客戶機狀態區還包括非物理寄存器的內容,比如一個 32 位的 Active State 值表明 Guest OS 執行時處理器所處的活躍狀態,如果正常執行指令就是處於 Active 狀態,如果觸發了三重故障(Triple Fault)或其它嚴重錯誤就處於 Shutdown 狀態,等等。

執行控制區用於存放可以操控 VM entry 和 VM exit 的標誌位,包括:

External-interrupt exiting:用於設置是否外部中斷可以觸發 VM exit,而不論 Guest OS 是否屏蔽了中斷。

Interrupt-window exiting:如果設置,當 Guest OS 解除中斷屏蔽時,觸發 VM exit。

Use TPR shadow:通過 CR8 訪問 Task Priority Register(TPR)的時候,使用 VMCS 中的影子 TPR,可以避免觸發 VM exit。同時執行控制區還有一個 TPR 閾值的設置,只有當 Guest OS 設置的 TR 值小於該閾值時,才觸發 VM exit。

CR masks and shadows:每個控制寄存器的每一位都有對應的掩碼,控制 Guest OS 是否可以直接寫相應的位,或是觸發 VM exit。同時 VMCS 中包括影子控制寄存器,Guest OS 讀取控制寄存器時,硬體將影子控制寄存器的值返回給 Guest OS。

VMCS 還包括一組點陣圖以提供更好的適應性:

Exception bitmap:選擇哪些異常可以觸發 VM exit,

I/O bitmap:對哪些 16 位的 I/O 埠的訪問觸發 VM exit。

MSR bitmaps:與控制寄存器掩碼相似,每個 MSR 寄存器都有一組「讀」的點陣圖掩碼和一組「寫」的點陣圖掩碼。

每次發生 VM exi t時,硬體自動在 VMCS 中存入豐富的信息,方便 VMM 甄別事件的種類和原因。VM entry 時,VMM 可以方便地為 Guest OS 注入事件(中斷和異常),因為 VMCS 中存有 Guest OS 的中斷描述表(IDT)的地址,因此硬體能夠自動地調用 Guest OS 的處理程序。

傳統的全虛擬化實現在有了硬體的輔助之後,由於 CPU 引入了新的操作模式,VMM 和 Guest OS 的執行由硬體自動隔離開來,任何關鍵的事件都可以將系統控制權自動轉移到 VMM,因此 VMM 能夠完全控制系統的全部資源。Guest OS 也可以運行在它所期望的最高特權級別,因此特權級壓縮和特權級別名的問題迎刃而解,而且 Guest OS 中的系統調用也不會觸發 VM exit。

硬體使用物理地址訪問虛擬機控制塊(VMCS),而 VMCS 保存了 VMM 和 Guest OS 各自的 IDTR 和 CR3 寄存器,因此 VMM 可以擁有獨立的地址空間,Guest OS 能夠完全控制自己的地址空間,地址空間壓縮的問題也不存在了。中斷和異常虛擬化的問題也得到了很好的解決。VMM 只用簡單地設置需要轉發的虛擬中斷或異常,在 VM entry 時,硬體自動調用 Guest OS 的中斷和異常處理程序,大大簡化 VMM 的設計。同時,Guest OS 對中斷的屏蔽及解除可以不觸發 VM exit,從而提高了性能。而且 VMM 還可以設置當 Guest OS 解除中斷屏蔽時觸發 VM exit,因此能夠及時地轉發積累的虛擬中斷和異常。另外,純軟體實現的 VMM 目前缺少對 64 位客戶操作系統的支持,而 CPU 的虛擬化技術除支持廣泛的傳統操作系統類型之外,還支持 64 位客戶操作系統。硬體輔助虛擬技術提高了虛擬機的性能以及兼容性。

需要注意的是,上文中我們提到了全虛擬化、半虛擬化和硬體輔助的全虛擬化,但這種分類實際上並不絕對,一個優秀的 VMM 往往融合了多項技術。例如 VMware Workstation 是一個著名的全虛擬化的 VMM,但是它使用了一種被稱為動態二進位翻譯(Binary Translation)的技術把對特權狀態的訪問轉換成對影子狀態的操作,從而避免了低效的 Trap-And-Emulate 的處理方式,這與半虛擬化相似,只不過半虛擬化是靜態地修改程序代碼。

看得出硬體輔助虛擬化技術必然是未來的方向,Intel-VT 的處理器級虛擬化技術還需要進行以下優化:

提高操作模式間的轉換速度:兩種操作模式間的轉換髮生之如此頻繁,如果不能有效減少其轉換速度,即使充分利用硬體特性,虛擬機的整體性能也會大打折扣。早期的支持硬體輔助虛擬化技術的 Pentium 4 處理器需要花費 2409 個時鐘周期處理 VM entry,花費 508 個時鐘周期處理由缺頁異常觸發的 VM exit,代價相當高。隨著 Intel 技術的不斷完善,在新的 Core 架構上,相應時間已經減少到 937 和 446 個時鐘周期。未來硬體廠商還需要進一步提高模式的轉換速度,並提供更多的硬體特性來減少不必要的轉換。

優化翻譯後援緩衝器(TLB)的性能:每次 VM entry 和 VM exit 發生時,由於需要重新載入 CR3 寄存器,因此 TLB(Translation Lookaside Buffer)被完全清空。虛擬化系統中操作模式的轉換髮生頻率相當高,因此系統的整體性能受到明顯損害。一種可行的方案是為 VMM 和每個虛擬機分配一個全局唯一 ID,TLB 的每一項附加該 ID 信息來索引線性地址的翻譯。

提供內存管理單元(MMU)虛擬化的硬體支持:即使使用 Intel-VT 技術,VMM 還是得用老辦法來處理 Guest OS 中發生的缺頁異常以及Guest OS 的客戶機物理地址到主機物理地址的翻譯,本質原因是 VMM 完全控制主機物理內存,因此 Guest OS 中的線性地址的翻譯同時牽涉到 VMM 和 Guest OS 的地址空間,而硬體只能看到其中的一個。Intel 和 AMD 提出了各自的解決方案,分別叫做 EPT(Extended Page Table)和 Nested Paging。這兩種技術的基本思想是,無論何時遇到客戶機物理地址,硬體自動搜索 VMM 提供的關於該 Guest OS 的一個頁表,翻譯成主機物理地址,或產生缺頁異常來觸發 VM exit。

支持高效的 I/O 虛擬化:I/O 虛擬化需要考慮性能、可用性、可擴展性、可靠性和成本等多種因素。最簡單的方式是 VMM 為虛擬機模擬一個常見的 I/O 設備,該設備的功能由 VMM 用軟體或復用主機 I/O 設備的方法實現。例如 Virtual PC 虛擬機提供的是一種比較古老的 S3 Trio64顯卡。這種方式提高了兼容性,並充分利用 Guest OS 自帶的設備驅動程序,但是虛擬的 I/O 設備功能有限且性能低下。為了提高性能,VMM 可以直接將主機 I/O 設備分配給虛擬機,這會帶來兩個主要挑戰:1. 如果多個虛擬機可以復用同一個設備,VMM 必須保證它們對設備的訪問不會互相干擾。2. 如果 Guest OS 使用 DMA 的方式訪問 I/O 設備,由於 Guest OS 給出的地址並不是主機物理地址,VMM 必須保證在啟動 DMA 操作前將該地址正確轉換。Intel 和 AMD 分別提出了各自的解決方案,分別稱為 Direct I/O(VT-d)和 IOMMU,希望用硬體的手段解決這些問題,降低 VMM 實現的難度。

2004 年,微軟發布 Virtual Server 2005 計劃,象徵著虛擬化技術正式進入主流市場。

2005 年,OpenVZ 發布,這是 Linux 操作系統的容器化技術實現,同時也是 LXC 的核心實現。

2006 年,Intel 和 AMD 等廠商相繼將對虛擬化技術的支持加入到 x86 體系結構的中央處理器中(AMD-V,Intel VT-x),使原來純軟體實現的各項功能可以用藉助硬體的力量實現提速。同年,紅帽將 Xen 作為 RHEL 的默認特性。同年,Amazon Web Services(AWS)開始以 Web 服務的形式向企業提供 IT 基礎設施服務,現在通常稱為雲計算。

ps:虛擬化和雲計算不解的淵源自此開始了。

2007 年 1 月,Sun 公司發布了開源虛擬化軟體 VirtualBox。同年 Xen 被 Citrix(思傑)收購。

2007 年 2 月,Linux Kernel 2.6.20 合入了由以色列公司 Qumranet 開發的虛擬化內核模塊 KVM(Kernel-based Virtual Machine,基於內核的虛擬機),支持 KVM 的前提是 CPU 必須要支持虛擬化技術。

2008 年第一季度,微軟同時發布了 Windows Server 2008 R2 及虛擬化產品 Hyper-V。

2008 年 6 月,Linux Container(LXC) 發布 0.1.0 版本,其可以提供輕量級的虛擬化,用來隔離進程和資源。是 Docker 最初使用的容器技術支撐。

2008 年 9 月 4 日,Red Hat 收購以色列公司 Qumranet,並著手使用 KVM 替換在 Red Hat 中的使用的 Xen。

2009 年 9 月,紅帽發布 RHEL 5.4,在原先的 Xen 虛擬化機制之上,將 KVM 添加了進來。同年,阿里雲寫下第一行代碼。

2010年11月,紅帽發布 RHEL 6.0,這個版本將默認安裝的 Xen 虛擬化機制徹底去除,僅提供 KVM 虛擬化機制。

當年,Xen 雖然作為一項廣泛應用於 Linux 發行版中的虛擬化技術,但卻遲遲沒有集成到 Linux 內核中,紅帽也許是出於對這種脫離內核的維護方式感到不爽,加之當時思傑和微軟表現的很非常親密,導致紅帽萌生了放棄 Xen 的想法,並在正式採用 KVM 的一年後,就宣布徹底放棄 Xen。硬體輔助虛擬化的到來,Xen 引以為傲的半虛擬化技術也隨之在主流 Linux 發行廠商中衰落了。

2010 年 10 月 21 日,NASA 發布了可以 IaaS(基礎設施即服務)雲操作系統 OpenStack,第一個版本便是眾所周知 Austin(奧斯丁)。OpenStack 挽手自主可控的口號,推動了雲計算在國內的全面爆發。

2011 年初,IBM 找上老搭檔紅帽,表示 KVM 這個東西值得加大力度去做。於是到了 5 月,IBM 和紅帽,聯合惠普和英特爾一起,成立了開放虛擬化聯盟(Open Virtualization Alliance),加速 KVM 投入市場的速度,由此避免 VMware 一家獨大的情況出現。聯盟成立之時,紅帽的發言人表示:「大家都希望除 VMware 之外還有一種開源選擇。未來的雲基礎設施一定會基於開源。我們想要營造一個小廠商們可以輕鬆加入的生態環境。」

ps:現在回頭再看,企業之所以能夠長盛不衰,長遠的洞察力至關重要。

操作系統虛擬化(容器)

2013 年 3 月 15 日,在加利福尼亞州聖克拉拉召開的 Python 開發者大會上,DotCloud 的創始人兼首席執行官 Solomon Hvkes 在一場僅五分鐘的微型演講中,首次提出了 Docker 這一概念,並於會後將其源碼開源並託管到 Github。最初的 Docker 就是使用了 LXC 再封裝了其他的一些功能。可以看出,Docker 的成功,與其說是技術的創新,還不如說是一次組合式的創新。

2014 年 6 月,Docker 發布了第一個正式版本 v1.0。同年,Redhat 和 AWS 就宣布了為 Docker 提供官方支持。

在傳統操作系統中,所有用戶的進程本質上是在同一個操作系統的實例中運行,因此內核或應用程序的缺陷可能影響到其它進程。操作系統虛擬化(OS-level virtualization) 是一種在伺服器操作系統中使用的、沒有 VMM 層的輕量級虛擬化技術,內核通過創建多個虛擬的操作系統實例(內核和庫)來隔離不同的進程(容器),不同實例中的進程完全不了解對方的存在。

操作系統虛擬化看似與上述提到過的幾種硬體虛擬化方式一樣,都是產生多個操作系統,但操作系統虛擬化與硬體虛擬化之間還是有很多不同之處,其中最核心的區別就是:操作系統虛擬化是操作系統的虛擬化,而硬體虛擬化是計算機的虛擬化。前者隔離操作系統資源,而後者隔離計算機硬體資源。

ps:容器技術之所以火熱,是因為容器隔離性封裝的特性,為運維能力引入了 「可編程性」,開發人員藉助容器得以 Software Define Operation。

2015 年 7 月 21 日:Kubernetes v1.0 發布!進入雲原生時代。

2018 年,IBM 正式收購 Redhat 以彌補在雲計算市場的戰略失敗。同年,微軟收購 Github。開源的歷史會銘記這一天。

2019 年,全球最大的開源盛會 KubeCon CloudNativeCon Open Source Summit、Open Infrastructure Summit 相繼在上海舉辦。中國的開源會銘記這一天。

註:本篇文章將會一直更新下去!

最後

對於篇幅較長的文章,我都習慣使用三句話來進行總結:

虛擬化的發展:縱觀虛擬化技術的發展歷史,可以看到它始終如一的目標就是實現對 IT 資源的充分利用。

虛擬化與雲計算:虛擬化是 IT 資源的抽象,雲計算則是基於虛擬化實現的更上層的對企業業務能力的抽象。

雲計算與開源:開源是引誘開發者的蘋果,而開發者則是企業的核心資產。雲的世界,得開發者,得天下。

參考文檔

https://www.ibm.com/developerworks/cn/linux/l-cn-vt/index.html

作者:范桂颶,九州雲(99Cloud)OpenStack 研發工程師,曾先後服務於 Windows Azure、Redhat OpenStack 與 Prophetech HyperMotion。雲物互聯公號主,現專註於探索雲計算、邊緣計算、SDN 與物聯網的深度結合應用場景。

聲明:本文首發於作者的 CSDN 博客,已獲作者授權,原文:https://blog.csdn.net/Jmilk/article/details/99675664。

【END】

熱 文推 薦

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 CSDN 的精彩文章:

《長安十二時辰》火了!程序員版本過於真實
拿來就能用!去哪兒網消息中間件 QMQ 詳解 | 技術頭條

TAG:CSDN |