KVM中的網路IO裝置虛擬化方式
在KVM虛擬化的架構裡,對CPU的虛擬化採用的是硬體輔助的方式(Intel VT-x,AMD-V),效率比較高,記憶體的虛擬化有Intel EPT技術的支援,效率也沒有問題;那麼對於像磁碟驅動器,網絡卡等io裝置來說,KVM提供兩種虛擬化方式:採用全虛擬化純軟體實現的QEMU/KVM方式,採用半虛擬化的virtio方式。
如上圖,在一些桌面虛擬化產品裡,預設採用的是QEMU/KVM方式對磁碟,網絡卡裝置進行虛擬化
對於大多數採用開源KVM方案的桌面虛擬化產品來說,通過在客戶機作業系統裡安裝增強工具,可以將io裝置的虛擬化方式改成virtio,從而增強效能
下面分別介紹下這兩種虛擬化方式的實現原理:
(一)利用QEMU來模擬IO裝置
QEMU以純軟體的方式來模擬IO裝置的執行
當客戶機的裝置驅動程式發起IO請求時,核心KVM模組會截獲這次請求,然後經過翻譯將本次請求放到記憶體裡的IO共享頁面,並通知客戶機QEMU模擬程序(客戶虛擬機器也是底層Linux系統裡的一個使用者空間程序QEMU-KVM,這是KVM裡很重要的一個概念)來處理本次請求,這裡KVM模組起的是一個傳達的作用,傳統的在物理機上執行的程式好比你在餐廳裡吃飯,你直接通過服務員(驅動)告訴廚師(硬體)你要吃什麼菜,而虛擬化環境裡就像在網上叫外賣,你無需知道餐廳在哪,你(客戶虛擬機器)只需要通知外賣平臺(KVM模組)你要吃某個菜(執行一次IO操作),剩下的事情就是由外賣平臺去與具體的餐廳協調,保證按時將外賣送到你手上。
從技術的角度來說,核心KVM模組是一個程序,QEMU模擬程式也是一個程序,IO請求的翻譯和傳達實際上是進行了一次程序間通訊(IPC),而實現方式是由KVM模組將攔截的請求放到記憶體裡的IO共享頁,共享記憶體(shared memory)正是IPC最快的實現方式,當一個程序寫共享記憶體,其他程序都立即知道寫入的內容,而且可以訪問。
QEMU模擬程式獲知了本次IO操作的具體資訊後,交由硬體模擬程式碼(Emulation Code)來執行本次IO操作,通過Linux核心裡的物理硬體驅動,來呼叫物理IO裝置完成IO操作,並返回所期望得到的值,再將這個值放回IO共享頁,通知KVM模組讀取這個值,並轉交給客戶虛擬機器上的IO裝置驅動。
通過QEMU模擬IO裝置,優點是可以模擬出各種各樣的硬體,包括一些老的,不常用的裝置,相容性比較廣泛,而且不用修改客戶機作業系統,就可以讓模擬裝置在客戶機上正常工作。但缺點也很大,每次IO路徑太長,大量程序間通訊有可能帶來的阻塞(雖然阻塞不分配CPU時間片,但也要進行執行緒的掛起和喚醒),而且所有的IO指令都是敏感指令也是特權指令(Ring1),也會帶來VMExit,VMEntry的開銷,且IO返還值的傳遞也要進行多次資料複製,故效能較差。
(二)VirtIO半虛擬化IO裝置
VirtIO是執行在Hypervisor上的一個抽象的API介面,通過讓客戶機知道自己執行在虛擬化環境裡,進而根據virtio標準與Hypervisor進行協作,從而獲得更好的IO效能。
其基本結構如下圖
其前端驅動frontend是執行在客戶虛擬機器上的驅動程式模組(也就是我們在桌面上安裝的虛擬機器增強工具,裡面包含了如virtio-blk,virtio-net等驅動),而後端處理程式backend是在QEMU裡實現的,這種類似於C/S架構的方式遮蔽了底層裝置驅動之間的差異,虛擬機器中的virtio驅動與QEMU之間通過標準化介面進行通訊,不需要經過複雜的翻譯轉換(而是類似一箇中國人和一個日本人,都用對方能懂的語言比如英語溝通,大家一起去完成某個任務),所以效率較高。
在前後端驅動之間,還定義了兩層資料結構來對通訊進行處理,其中virtio這一層是虛擬佇列介面(佇列最大的特點是FIFO,先提交的請求先執行),每個虛擬機器都有自己的虛擬佇列,這也是IO虛擬化和CPU虛擬化之間的區別,沒有時間片的分配,所有虛擬機器的io請求搶佔現有資源,至於怎麼對IO做Qos控制,還在學習中,不敢妄言,各個廠家的實現方式似乎並不相同,以後有機會再總結。從邏輯上看,虛擬佇列介面就是連線前端驅動和後端處理程式的通道,一個前端驅動可以同時使用若干個虛擬佇列,比如對virtio-net網路驅動同時使用2個虛擬佇列(一個用於傳送,一個用於接受),而virtio-blk塊裝置驅動只需要使用一個虛擬佇列。virtio的下層是virtio-ring的資料結構,這是一個環形緩衝區(又叫迴圈佇列,也是佇列的一種),作用是儲存前端驅動的多次請求,再批量交給後端驅動處理,同時防止佇列溢位(迴圈佇列的特點),通過這種設計約定實現批量處理而不用對客戶機的每個io請求進行一次處理,大大提高了客戶機與Hypervisor層的協作效率。
virtio的半虛擬化驅動方式,有很高的io效能,幾乎和直接跑在硬體上一樣,因此只要可能,使用virtio是高效的選擇,不過其缺點是需要更改客戶機的作業系統,使之知道自己跑在虛擬化環境裡(在一些桌面虛擬化產品裡,是通過在客戶機系統裡安裝虛擬化增強工具來實現的),同時要求客戶虛擬機器和宿主機的Linux核心都支援virtio(好比之前的例子裡,中國人和日本人都得懂英文,不然還是得等翻譯),目前在比較新的Linux(核心版本2.6.24及以上)都支援virtio,所以長遠看通過virtio進行io裝置的虛擬化是必然。