說一說虛擬化繞不開的IO半虛擬化
QEMU-KVM作為一個VMM提供了全虛擬化環境,guest不經過任何修改就能運行在KVM環境中。不過KVM在IO虛擬化方面,使用QEMU純軟件的方式來模擬IO設備,效率并不高。在KVM中,要想提高IO虛擬化的效率,就要使用半虛擬化的方式:virtio。
簡單介紹全虛擬化和半虛擬化
在全虛擬化 中,guest操作系統運行在VMM之上,并不知道它已被虛擬化,不需要任何更改就可以工作。相反,在半虛擬化中,guest操作系統不僅知道它運行在 VMM上,還需要做修改來對接VMM的代碼。
在全虛擬化中,VMM必須模擬設備硬件,盡管這種模擬很徹底很干凈,但它效率低代碼最復雜。在半虛擬化模式中,guest和 VMM共同合作,模擬更加高效。
IO全虛擬化使用QEMU軟件模擬
1.當虛擬機進行I/O操作時,根據《也談Intel的cpu虛擬化》我們知道,虛擬機通過VM exit將cpu控制權返回給VMM,從而陷入到root模式下的ring0內的VMM,進行”陷入模擬“。
2.將本次I/O請求的信息存放到IO共享頁,QEMU從IO共享頁讀取信息后由硬件模擬代碼來模擬出本次的IO操作,并調用內核中的硬件驅動把IO請求發送到物理硬件,完成之后將結果放回到IO共享頁。
3.KVM模塊中的捕獲代碼讀取IO共享頁中的結果,把結果返回到guest。
4.通過VM entry,guest再次獲得cpu控制權,根據IO返回的結果進行處理。
說明:VMM和guest的IO信息共享不光IO共享頁一種,還可以使用DMA。QEMU不把IO結果放到IO共享頁中,而是通過DMA將結果直接寫到guest的內存中去,然后通過KVM模塊告訴客戶機DMA操作已經完成。
下面這張圖(來自網絡)是軟件模擬IO的流程圖:
IO半虛擬化virtio
guest和host使用使用virtio前后端的技術減少了guest IO時的VM Exit(guest和host的上下文切換)并且使guest和host能并行處理IO來提高throughput和減少latency。但是IO的路徑并沒有比全虛擬化技術減少。下面是virtio的IO路徑:
guest在IO請求時,首先guest需要切換到host kernel,然后host kernel會切換到hyperisor來處理guest的請求,hypervisor通過系統調用將數據包發送到外部網絡后切換回host kernel,然后再切換回guest。這個長IO路徑和全虛擬化時相同的,只是減少了VM exit和VM entry。
vhost
為了解決virio的IO路徑太長的問題,vhost產生了。它是位于host kernel的一個模塊,用于和guest直接通信,所以數據交換就在guest和host kernel間進行,減少了上下文的切換。vhost相對與virto架構,把virtio驅動后端驅動從用戶態放到了內核態中(vhost的內核模塊充當virtiO后端驅動)
下面這張圖(來自redhat)描述了在virtio和vhost(vhost-net時vhost架構中的網卡實現)架構下內核的不同工作流程:
下面這張圖(來自intel)介紹了vhost工作原理:
vhost-user
vhost-user和vhost類似,只是使用一個用戶態進程vhost-user代替了內核中的vhost模塊。vhost-user進程和Guset之間時通過共享內存的方式進行數據操作。vhost-user相對與vhost架構,把virtio驅動后端驅動從內核態又放回到了用戶態中(vhost-user進程充當virtiO后端驅動)。
下面這張圖(來自intel)介紹了vhost-user的工作原理:
總結
io虛擬化經歷了從全虛擬化io到半虛擬化virtio。半虛擬化的后端驅動又經歷了從VMM中到內核中,從內核中到用戶空間中的過程。