本文首發於我的公眾號 Linux雲計算網絡(id: cloud_dev),專注於干貨分享,號內有 10T 書籍和視頻資源,后台回復「1024」即可領取,歡迎大家關注,二維碼文末可以掃。
前面 虛擬化技術總覽 中從虛擬平台 VMM 的角度,將虛擬化分為 Hypervisor 模型和宿主模型,如果根據虛擬的對象(資源類型)來划分,虛擬化又可以分為計算虛擬化、存儲虛擬化和網絡虛擬化,再細一些,又有中斷虛擬化,內存虛擬化,字符/塊設備虛擬化,網絡功能虛擬化等。
我會將此作為一個系列來寫,本文先看 CPU 虛擬化。在這之前,我們先來籠統看下虛擬化的本質是什么,它到底是如何做到將 Host 的硬件資源虛擬化給 Guest 用,我這里用兩個詞來定義,intercept 和 virtualize,中文翻譯成截獲和模擬比較恰當一點,這兩個詞基本上是虛擬化的終極定義了,帶着這兩個詞去看每一種虛擬化類型,會發現很容易理解和記憶。
CPU 軟件虛擬化
基於軟件的 CPU 虛擬化,故名思議,就是通過軟件的形式來模擬每一條指令。通過前面的文章我們知道常用的軟件虛擬化技術有兩種:優先級壓縮和二進制代碼翻譯。這兩種是通用技術,可以用在所有虛擬化類型中。我們就結合 intercept 和 virtualize 來看看 CPU 軟件虛擬化是怎么做的。
首先,一些必須的硬件知識要知道,X86 體系架構為了讓上層的軟件(操作系統、應用程序)能夠訪問硬件,提供了四個 CPU 特權級別,Ring 0 是最高級別,Ring 1 次之,Ring 2 更次之,Ring 3 是最低級別。
一般,操作系統由於要直接訪問硬件和內存,因此它的代碼需要運行在最高級別 Ring 0 上,而應用程序的代碼運行在最低級別 Ring 3 上,如果要訪問硬件和內存,比如設備訪問,寫文件等,就要執行相關的系統調用,CPU 的運行級別發生從 Ring 3 到 Ring 0 的切換,當完成之后,再切換回去,我們熟悉的用戶態和內核態切換的本質就來自這里。
虛擬化的實現也是基於這個思想,VMM 本質上是個 Host OS,運行在 Ring 0 上,Guest OS 運行在 Ring 1 上,再往上是相應層次的應用程序運行在 Ring 2 和 Ring 3 上。
當 Guest OS 或上層應用在執行相關的特權指令時,就會發生越權訪問,觸發異常,這個時候 VMM 就截獲(intercept)這個指令,然后模擬(virtualize)這個指令,返回給 Guest OS,讓其以為自己的特權指令可以正常工作,繼續運行。整個過程其實就是優先級壓縮和二進制代碼翻譯的體現。
CPU 硬件虛擬化
上面的這種截獲再模擬的純軟件的虛擬化方式,勢必是性能非常低的。那怎么樣提高性能呢,有一種改進的方式是修改 Guest OS 中關於特權指令的相關操作,將其改為一種函數調用的方式,讓 VMM 直接執行,而不是截獲和模擬,這樣就能在一定程度上提高性能。
但這種方式並不通用,要去改 Guest OS 的代碼,只能看作是一種定制。為了能夠通用,又能夠提高性能,就只能從硬件上去做文章了。所以,后來,以 Intel 的 VT-x 和 AMD 的 AMD-V 為主的硬件輔助的 CPU 虛擬化就被提出來(Intel VT 包括 VT-x (支持 CPU 虛擬化)、EPT(支持內存虛擬化)和 VT-d(支持 I/O 虛擬化))。
CPU 硬件輔助虛擬化在 Ring 模式的基礎上引入了一種新的模式,叫 VMX 模式。它包括根操作模式(VMX Root Operation)和非根操作模式(VMX Non-Root Operation)。
這兩種模式都有 Ring 0 - Ring 3 的特權級。所以,在描述某個應用程序時,除了描述其屬於哪個特權級,還要指明其處於根模式還是非根模式。
引入這種模式的好處就在於,Guest OS 運行在 Ring 0 上,就意味着它的核心指令可以直接下達到硬件層去執行,而特權指令等敏感指令的執行則是由硬件輔助,直接切換到 VMM 執行,這是自動執行的,應用程序是感知不到的,性能自然就提高了。
這種切換 VT-x 定義了一套機制,稱為 VM-entry 和 VM-exit。從非根模式切換到根模式,也就是從 Guest 切換到 Host VMM,稱為 VM-exit,反之稱為 VM-entry。
-
VM-exit : 如果 Guest OS 運行過程中遇到需要 VMM 處理的事件,比如中斷或缺頁異常,或者主動調用 VMCALL 指令調用 VMM 服務的時候(類似於系統調用),硬件自動掛起 Guest OS,切換到根模式,VMM 開始執行。
-
VM-entry: VMM 通過顯示調用 VMLAUNCH 或 VMRESUME 指令切換到非根模式,硬件自動加載 Guest OS 的上下文,Guest OS 開始執行。
KVM CPU 虛擬化
KVM 是一種硬件輔助的虛擬化技術,支持 Intel VT-x 和 AMD-v 技術,怎么知道 CPU 是否支持 KVM 虛擬化呢?可以通過如下命令查看:
# grep -E '(vmx|svm)' /proc/cpuinfo
如果輸出是 vmx 或 svm,則表明當前 CPU 支持 KVM,Intel 是 vmx,AMD 是svm。
從本質上看,一個 KVM 虛擬機對應 Host 上的一個 qemu-kvm 進程,它和其他 Linux 進程一樣被調度,而 qemu-kvm 進程中的一個線程就對應虛擬機的虛擬 CPU (vCPU),虛擬機中的任務線程就被 vCPU 所調度。
比如下面這個例子,Host 機有兩個物理 CPU,上面起了兩個虛擬機 VM1 和 VM2,VM1 有兩個 vCPU,VM2 有 3 個 vCPU,VM1 和 VM2 分別有 2 個 和 3 個線程在 2 個物理 CPU 上調度。VM1 和 VM2 中又分別有 3 個任務線程在被 vCPU 調度。
所以,這里有兩級的 CPU 調度,Guest OS 中的 vCPU 負責一級調度,Host VMM 負責另一級調度,即 vCPU 在物理 CPU 上的調度。
我們也可以看到,vCPU 的個數,可以超過物理 CPU 的個數,這個叫 CPU 「超配」,這正是 CPU 虛擬化的優勢所在,這表明了虛擬機能夠充分利用 Host 的 CPU 資源,進行相應的業務處理,運維人員也可以據此控制 CPU 資源使用,達到靈活調度。
OK,CPU 虛擬化就到這里,下篇文章將講述內存虛擬化。覺得寫得湊合可以給個贊,謝謝大家的支持。
我的公眾號 「Linux雲計算網絡」(id: cloud_dev) ,號內有 10T 書籍和視頻資源,后台回復 「1024」 即可領取,分享的內容包括但不限於 Linux、網絡、雲計算虛擬化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++編程技術等內容,歡迎大家關注。