天天看點

聊聊KVM的半虛拟化virtio驅動

作者:雲原生驿站

QEMU/KVM提供了全虛拟化環境,可以讓客戶機不經過任何修改就能運作在KVM環境當中。不過,KVM在I/O虛拟化方面,傳統的方式是使用QEMU純軟體的方式來模拟I/O裝置,其效率并不高。在KVM中,可以在客戶機使用半虛拟化驅動(Paravirtualized Drives,PV Drivers)來提高客戶機的性能。目前KVM使用中實作半虛拟化的方式是采用virtio這個Linux上的裝置驅動标準架構。

實作IO虛拟化主要有三種方式:全虛拟化、半虛拟化和透傳。全虛拟化Guest OS不會感覺到自己是虛拟機,也無需修改Guest OS,但是它的效率比較低。半虛拟化Guest OS知道自己是虛拟機,通過Frontend/Backend驅動模拟實作IO虛拟化。透傳就是直接配置設定實體裝置給VM用。Virtio是一種半虛拟化的裝置抽象接口規範,在Qemu和KVM中得到了廣泛使用

QEMU模拟I/O裝置的基本原理和優缺點

聊聊KVM的半虛拟化virtio驅動

在使用QEMU模拟I/O的情況下,當客戶機中的裝置驅動程式(Device Driver)發起I/O操作請求時,KVM子產品中的I/O操作捕獲代碼會攔截這次I/O請求,然後在經過處理後将本地I/O請求的資訊存放到I/O共享頁(sharing page),并通知使用者空間的QEMU程式。QEMU模拟程式獲得I/O操作的具體資訊之後,交由硬體模拟代碼(Emulation Code)來模拟出本次的I/O操作,完成之後,将本次結果放回到I/O共享頁。并通知KVM子產品中的I/O操作捕獲代碼。最後,由KVM子產品中的捕獲代碼讀取I/O共享頁的操作結果,并把結果傳回給客戶機中。

在這個操作的過程當中,客戶機作為一個QEMU程序在等待I/O時也可能被阻塞。另外,當客戶機通過DMA(Direct Memory Access)通路大塊I/O時,QEMU模拟程式将不會把操作結果放到I/O共享頁,而是通過記憶體映射的方式将結果直接寫到客戶機的記憶體中去,然後通過KVM子產品告訴客戶機DMA操作已經完成。

優點:

QEMU 可以模拟多種類型的 I/O 裝置,包括磁盤、網卡、聲霸卡等,可以滿足各種應用場景的需求。使用者可以自定義 I/O 裝置的參數和配置,以滿足特定的需求。

缺點:

每次I/O操作的路徑比較長,有較多的VMEntry、VMExit發生,需要多次上下文切換(context witch),也需要多次資料複制,是以性能比較差。

virtio的提出及原理

virtio最初由澳洲的一位天才級程式員Rusty Russell編寫,是一個在Hypervisor之上的抽象API接口,讓客戶機知道自己運作在虛拟化環境當中,進而根據virtio标準與Hypervisor協作,進而在客戶機當中達到更好的性能(特别是I/O性能)。

virtio的作用

virtio

為各種各樣裝置(如:網絡裝置、塊裝置等等)的虛拟提供了通用的标準化前端接口,增加了各個虛拟化平台的代碼複用。而不是各自為政般的使用繁雜的裝置虛拟機制。

virtio架構

virtio的基本結構如下

聊聊KVM的半虛拟化virtio驅動

五種前端驅動:

  • 塊裝置驅動(virtio-blk)
  • 網絡裝置(virtio-net)
  • PCI仿真(virtio-pci)
  • balloon驅動(virtio-balloon,用于動态管理客戶機記憶體使用)
  • scsi驅動
  • 終端驅動
每一個前端驅動,在hypervisor當中都有一個相比對的後端驅動

在前後端驅動之間,還定義了兩層來支援客戶機與QEMU之間的通信。其中virtio這一層是虛拟機隊列的接口,虛拟隊列(Virtual Queue)接口将前端驅動和後端驅動結合在一起。驅動可以有0個或多個隊列。

例如virtio-net網絡驅動程式使用兩個虛拟隊列(一個用于接收,另一個用于發送),而

virtio

塊裝置驅動隻需要一個

virtio-ring: 虛拟隊列,通常使用環形緩沖,在客戶機與虛拟機管理器之間傳輸

驅動檢視驗證

Linux核心現在已經預設開啟了virtio的驅動,以我本地的Linux為例:

[root@localhost ~]# uname -r
5.4.243-1.el7.elrepo.x86_64
[root@localhost ~]# find /lib/modules/5.4.243-1.el7.elrepo.x86_64/ -name virtio*.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/block/virtio_blk.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/char/hw_random/virtio-rng.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/char/virtio_console.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/crypto/virtio/virtio_crypto.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/gpu/drm/virtio/virtio-gpu.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/net/virtio_net.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/nvdimm/virtio_pmem.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/scsi/virtio_scsi.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/virtio/virtio.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/virtio/virtio_balloon.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/virtio/virtio_input.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/virtio/virtio_pci.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/drivers/virtio/virtio_ring.ko
/lib/modules/5.4.243-1.el7.elrepo.x86_64/kernel/fs/fuse/virtiofs.ko
           

繼續閱讀