KVM 介紹(3):I/O 全虛擬化和准虛擬化


在 QEMU/KVM 中,客戶機可以使用的設備大致可分為三類:
1. 模擬設備:完全由 QEMU 純軟件模擬的設備。
2. Virtio 設備:實現 VIRTIO API 的半虛擬化設備。
3. PCI 設備直接分配 (PCI device assignment) 。

1. 全虛擬化 I/O 設備

KVM 在 IO 虛擬化方面,傳統或者默認的方式是使用 QEMU 純軟件的方式來模擬 I/O 設備,包括鍵盤、鼠標、顯示器,硬盤 和 網卡 等。模擬設備可能會使用物理的設備,或者使用純軟件來模擬。模擬設備只存在於軟件中。 

1.1 原理

 
過程:
  1. 客戶機的設備驅動程序發起 I/O 請求操作請求
  2. KVM 模塊中的 I/O 操作捕獲代碼攔截這次 I/O 請求
  3. 經過處理后將本次 I/O 請求的信息放到 I/O 共享頁 (sharing page),並通知用戶空間的 QEMU 程序。
  4. QEMU 程序獲得 I/O 操作的具體信息之后,交由硬件模擬代碼來模擬出本次 I/O 操作。
  5. 完成之后,QEMU 將結果放回 I/O 共享頁,並通知 KMV 模塊中的 I/O 操作捕獲代碼。
  6. KVM 模塊的捕獲代碼讀取 I/O 共享頁中的操作結果,並把結果放回客戶機。 
注意:當客戶機通過DMA (Direct Memory Access)訪問大塊I/O時,QEMU 模擬程序將不會把結果放進共享頁中,而是通過內存映射的方式將結果直接寫到客戶機的內存中共,然后通知KVM模塊告訴客戶機DMA操作已經完成。
 
這種方式的優點是可以模擬出各種各樣的硬件設備;其缺點是每次 I/O 操作的路徑比較長,需要多次上下文切換,也需要多次數據復制,所以性能較差。 

1.2 QEMU 模擬網卡的實現

Qemu 純軟件的方式來模擬I/O設備,其中包括經常使用的網卡設備。Guest OS啟動命令中沒有傳入的網絡配置時,QEMU默認分配 rtl8139 類型的虛擬網卡類型,使用的是默認用戶配置模式,這時候由於沒有具體的網絡模式的配置,Guest的網絡功能是有限的。 全虛擬化情況下,KVM虛機可以選擇的網絡模式包括:

  1. 默認用戶模式(User);
  2. 基於網橋(Bridge)的模式;
  3. 基於NAT(Network Address Translation)的模式;

分別使用的 qemu-kvm 參數為:

  • -net user[,vlan=n]:使用用戶模式網絡堆棧,這樣就不需要管理員權限來運行.如果沒有指 定-net選項,這將是默認的情況.-net tap[,vlan=n][,fd=h]
  • -net nic[,vlan=n][,macaddr=addr]:創建一個新的網卡並與VLAN n(在默認的情況下n=0)進行連接。作為可選項的項目,MAC地址可以進行改變.如果 沒有指定-net選項,則會創建一個單一的NIC.
  • -net tap[,vlan=n][,fd=h][,ifname=name][,script=file]:將TAP網絡接口 name 與 VLAN n 進行連接,並使用網絡配置腳本文件進行 配置。默認的網絡配置腳本為/etc/qemu-ifup。如果沒有指定name,OS 將會自動指定一個。fd=h可以用來指定一個已經打開的TAP主機接口的句柄。

網橋模式是目前比較簡單,也是用的比較多的模式,下圖是網橋模式下的 VM的收發包的流程。

如圖中所示,紅色箭頭表示數據報文的入方向,步驟:

  1. 網絡數據從 Host 上的物理網卡接收,到達網橋;
  2. 由於 eth0 與 tap1 均加入網橋中,根據二層轉發原則,br0 將數據從 tap1 口轉發出去,即數據由 Tap設備接收;
  3. Tap 設備通知對應的 fd 數據可讀;
  4. fd 的讀動作通過 tap 設備的字符設備驅動將數據拷貝到用戶空間,完成數據報文的前端接收。

(引用自 http://luoye.me/2014/07/17/netdev-virtual-1/

 1.3 RedHat Linux 6 中提供的模擬設備

  • 模擬顯卡:提供2塊模擬顯卡。
  • 系統組件:
    • ntel i440FX host PCI bridge
    • PIIX3 PCI to ISA bridge
    • PS/2 mouse and keyboard
    • EvTouch USB Graphics Tablet
    • PCI UHCI USB controller and a virtualized USB hub
    • Emulated serial ports
    • EHCI controller, virtualized USB storage and a USB mouse
  • 模擬的聲卡:intel-hda
  • 模擬網卡:e1000,模擬 Intel E1000 網卡;rtl8139,模擬 RealTeck 8139 網卡。
  • 模擬存儲卡:兩塊模擬 PCI IDE 接口卡。KVM  限制每個虛擬機最多只能有4塊虛擬存儲卡。還有模擬軟驅。

注意:RedHat Linux KVM 不支持 SCSI 模擬。

在不顯式指定使用其它類型設備的情況下,KVM 虛機將使用這些默認的虛擬設備。比如上面描述的默認情況下 KVM 虛機默認使用rtl8139網卡。比如,在 RedHat Linxu 6.5 主機上啟動KVM RedHat Linux 6.4 虛機后,登錄虛機,查看 pci 設備,可以看到這些模擬設備:
 
當使用 “-net nic,model=e1000” 指定網卡model 為 e1000 時,

1.4 qemu-kvm 關於磁盤設備和網絡的主要選項

類型 選項
磁盤設備(軟盤、硬盤、CDROM等)
-drive option[,option[,option[,...]]]:定義一個硬盤設備;可用子選項有很多。
    file=/path/to/somefile:硬件映像文件路徑;
    if=interface:指定硬盤設備所連接的接口類型,即控制器類型,如ide、scsi、sd、mtd、floppy、pflash及virtio等;
    index=index:設定同一種控制器類型中不同設備的索引號,即標識號;
    media=media:定義介質類型為硬盤(disk)還是光盤(cdrom);    
    format=format:指定映像文件的格式,具體格式可參見qemu-img命令;
-boot [order=drives][,once=drives][,menu=on|off]:定義啟動設備的引導次序,每種設備使用一個字符表示;不同的架構所支持的設備及其表示字符不盡相同,在x86 PC架構上,a、b表示軟驅、c表示第一塊硬盤,d表示第一個光驅設備,n-p表示網絡適配器;默認為硬盤設備(-boot order=dc,once=d)
網絡
-net nic[,vlan=n][,macaddr=mac][,model=type][,name=name][,addr=addr][,vectors=v]:創建一個新的網卡設備並連接至vlan n中;PC架構上默認的NIC為e1000,macaddr用於為其指定MAC地址,name用於指定一個在監控時顯示的網上設備名稱;emu可以模擬多個類型的網卡設備;可以使用“qemu-kvm -net nic,model=?”來獲取當前平台支持的類型;
-net tap[,vlan=n][,name=name][,fd=h][,ifname=name][,script=file][,downscript=dfile]:通過物理機的TAP網絡接口連接至vlan n中,使用script=file指定的腳本(默認為/etc/qemu-ifup)來配置當前網絡接口,並使用downscript=file指定的腳本(默認為/etc/qemu-ifdown)來撤消接口配置;使用script=no和downscript=no可分別用來禁止執行腳本;
-net user[,option][,option][,...]:在用戶模式配置網絡棧,其不依賴於管理權限;有效選項有:
     vlan=n:連接至vlan n,默認n= 0
     name=name:指定接口的顯示名稱,常用於監控模式中;
     net=addr[/mask]:設定GuestOS可見的IP網絡,掩碼可選,默認為 10.0 . 2.0 / 8
     host=addr:指定GuestOS中看到的物理機的IP地址,默認為指定網絡中的第二個,即x.x.x. 2
     dhcpstart=addr:指定DHCP服務地址池中 16 個地址的起始IP,默認為第 16 個至第 31 個,即x.x.x. 16 -x.x.x. 31
     dns=addr:指定GuestOS可見的dns服務器地址;默認為GuestOS網絡中的第三個地址,即x.x.x. 3
     tftp=dir:激活內置的tftp服務器,並使用指定的dir作為tftp服務器的默認根目錄;
     bootfile=file:BOOTP文件名稱,用於實現網絡引導GuestOS;如:qemu -hda linux.img -boot n -net user,tftp=/tftpserver/pub,bootfile=/pxelinux. 0

 對於網卡來說,你可以使用 modle 參數指定虛擬網絡的類型。 RedHat Linux 6 所支持的虛擬網絡類型有:

[root@rh65 isoimages]# kvm -net nic,model=?
qemu: Supported NIC models: ne2k_pci,i82551,i82557b,i82559er,rtl8139,e1000,pcnet,virtio 

2. 准虛擬化 (Para-virtualizaiton) I/O 驅動 virtio

在 KVM 中可以使用准虛擬化驅動來提供客戶機的I/O 性能。目前 KVM 采用的的是 virtio 這個 Linux 上的設備驅動標准框架,它提供了一種 Host 與 Guest 交互的 IO 框架。

2.1 virtio 的架構

 KVM/QEMU 的 vitio 實現采用在 Guest OS 內核中安裝前端驅動 (Front-end driver)和在 QEMU 中實現后端驅動(Back-end)的方式。前后端驅動通過 vring 直接通信,這就繞過了經過 KVM 內核模塊的過程,達到提高 I/O 性能的目的。
 
 
純軟件模擬的設備和 Virtio 設備的區別:virtio 省去了純模擬模式下的異常捕獲環節,Guest OS 可以和 QEMU 的 I/O 模塊直接通信。
 
 
使用 Virtio 的完整虛機 I/O流程:
 
 
Host 數據發到 Guest:
1. KVM 通過中斷的方式通知 QEMU 去獲取數據,放到 virtio queue 中
2. KVM 再通知 Guest 去 virtio queue 中取數據。

2.2 Virtio 在 Linux 中的實現

 Virtio 是在半虛擬化管理程序中的一組通用模擬設備的抽象。這種設計允許管理程序通過一個應用編程接口 (API)對外提供一組通用模擬設備。通過使用半虛擬化管理程序,客戶機實現一套通用的接口,來配合后面的一套后端設備模擬。后端驅動不必是通用的,只要它們實現了前端所需的行為。因此,Virtio 是一個在 Hypervisor 之上的抽象API接口,讓客戶機知道自己運行在虛擬化環境中,進而根據 virtio 標准與 Hypervisor 協作,從而客戶機達到更好的性能。
  • 前端驅動:客戶機中安裝的驅動程序模塊
  • 后端驅動:在 QEMU 中實現,調用主機上的物理設備,或者完全由軟件實現。
  • virtio 層:虛擬隊列接口,從概念上連接前端驅動和后端驅動。驅動可以根據需要使用不同數目的隊列。比如 virtio-net 使用兩個隊列,virtio-block只使用一個隊列。該隊列是虛擬的,實際上是使用 virtio-ring 來實現的。
  • virtio-ring:實現虛擬隊列的環形緩沖區
 
Linux 內核中實現的五個前端驅動程序:
  • 塊設備(如磁盤)
  • 網絡設備
  • PCI 設備
  • 氣球驅動程序(動態管理客戶機內存使用情況)
  • 控制台驅動程序
Guest OS 中,在不使用 virtio 設備的時候,這些驅動不會被加載。只有在使用某個 virtio 設備的時候,對應的驅動才會被加載。每個前端驅動器具有在管理程序中的相應的后端的驅動程序。
 
以 virtio-net 為例,解釋其原理:

(1)virtio-net 的原理:

它使得:
  1. 多個虛機共享主機網卡 eth0
  2. QEMU 使用標准的 tun/tap 將虛機的網絡橋接到主機網卡上
  3. 每個虛機看起來有一個直接連接到主機PCI總線上的私有 virtio 網絡設備
  4. 需要在虛機里面安裝 virtio驅動

(2)virtio-net 的流程:

 
總結 Virtio 的優缺點:
  • 優點:更高的IO性能,幾乎可以和原生系統差不多。
  • 缺點:客戶機必須安裝特定的 virtio 驅動。一些老的 Linux 還沒有驅動支持,一些 Windows 需要安裝特定的驅動。不過,較新的和主流的OS都有驅動可以下載了。Linux 2.6.24+ 都默認支持 virtio。可以使用 lsmod | grep virtio 查看是否已經加載。

2.3 使用 virtio 設備 (以 virtio-net 為例)

使用 virtio 類型的設備比較簡單。較新的 Linux 版本上都已經安裝好了 virtio 驅動,而 Windows 的驅動需要自己下載安裝。

(1)檢查主機上是否支持 virtio 類型的網卡設備

[root@rh65 isoimages]# kvm -net nic,model=?
qemu: Supported NIC models: ne2k_pci,i82551,i82557b,i82559er,rtl8139,e1000,pcnet,virtio

(2)指定網卡設備model 為 virtio,啟動虛機

(3)通過 vncviewer 登錄虛機,能看到被加載了的 virtio-net 需要的內核模塊

(4)查看 pci 設備

其它 virtio 類型的設備的使用方式類似 virtio-net。

2.4 vhost-net (kernel-level virtio server)

  前面提到 virtio 在宿主機中的后端處理程序(backend)一般是由用戶空間的QEMU提供的,然而如果對於網絡 I/O 請求的后端處理能夠在在內核空間來完成,則效率會更高,會提高網絡吞吐量和減少網絡延遲。在比較新的內核中有一個叫做 “vhost-net” 的驅動模塊,它是作為一個內核級別的后端處理程序,將virtio-net的后端處理任務放到內核空間中執行,減少內核空間到用戶空間的切換,從而提高效率。

根據 KVM 官網的這篇文章,vhost-net 能提供更低的延遲(latency)(比 e1000 虛擬網卡低 10%),和更高的吞吐量(throughput)(8倍於普通 virtio,大概  7~8 Gigabits/sec )。

vhost-net 與 virtio-net 的比較:

vhost-net 的要求:

  • qemu-kvm-0.13.0 或者以上
  • 主機內核中設置 CONFIG_VHOST_NET=y 和在虛機操作系統內核中設置 CONFIG_PCI_MSI=y (Red Hat Enterprise Linux 6.1 開始支持該特性)
  • 在客戶機內使用 virtion-net 前段驅動
  • 在主機內使用網橋模式,並且啟動 vhost_net

qemu-kvm 命令的 -net tap 有幾個選項和 vhost-net 相關的: -net tap,[,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]

  • vnet_hdr =on|off:設置是否打開TAP設備的“IFF_VNET_HDR”標識。“vnet_hdr=off”表示關閉這個標識;“vnet_hdr=on”則強制開啟這個標識,如果沒有這個標識的支持,則會觸發錯誤。IFF_VNET_HDR是tun/tap的一個標識,打開它則允許發送或接受大數據包時僅僅做部分的校驗和檢查。打開這個標識,可以提高virtio_net驅動的吞吐量。
  • vhost=on|off:設置是否開啟vhost-net這個內核空間的后端處理驅動,它只對使用MIS-X中斷方式的virtio客戶機有效。
  • vhostforce=on|off:設置是否強制使用 vhost 作為非MSI-X中斷方式的Virtio客戶機的后端處理程序。
  • vhostfs=h:設置為去連接一個已經打開的vhost網絡設備。

vhost-net 的使用實例:

(1)確保主機上 vhost-net 內核模塊被加載了

(2)啟動一個虛擬機,在客戶機中使用 -net 定義一個 virtio-net 網卡,在主機端使用 -netdev 啟動 vhost

(3)在虛擬機端,看到 virtio 網卡使用的 TAP 設備為 tap0。

(4)在宿主機中看 vhost-net 被加載和使用了,以及 Linux 橋 br0,它連接物理網卡 eth1 和 客戶機使用的 TAP 設備 tap0

 

一般來說,使用 vhost-net 作為后端處理驅動可以提高網絡的性能。不過,對於一些網絡負載類型使用 vhost-net 作為后端,卻可能使其性能不升反降。特別是從宿主機到其中的客戶機之間的UDP流量,如果客戶機處理接受數據的速度比宿主機發送的速度要慢,這時就容易出現性能下降。在這種情況下,使用vhost-net將會是UDP socket的接受緩沖區更快地溢出,從而導致更多的數據包丟失。故這種情況下,不使用vhost-net,讓傳輸速度稍微慢一點,反而會提高整體的性能。

使用 qemu-kvm 命令行,加上“vhost=off”(或沒有vhost選項)就會不使用vhost-net,而在使用libvirt時,需要對客戶機的配置的XML文件中的網絡配置部分進行如下的配置,指定后端驅動的名稱為“qemu”(而不是“vhost”)。

<interface type=”network”>

    <model type=”virtio”/>

    <driver name=”qemu”/>

</interface>

2.6 virtio-balloon

另一個比較特殊的 virtio 設備是 virtio-balloon。通常來說,要改變客戶機所占用的宿主機內存,要先關閉客戶機,修改啟動時的內存配置,然后重啟客戶機才可以實現。而 內存的 ballooning (氣球)技術可以在客戶機運行時動態地調整它所占用的宿主機內存資源,而不需要關閉客戶機。該技術能夠:

  • 當宿主機內存緊張時,可以請求客戶機回收利用已分配給客戶機的部分內存,客戶機就會釋放部分空閑內存。若其內存空間不足,可能還會回收部分使用中的內存,可能會將部分內存換到交換分區中。
  • 當客戶機內存不足時,也可以讓客戶機的內存氣球壓縮,釋放出內存氣球中的部分內存,讓客戶機使用更多的內存。

目前很多的VMM,包括 KVM, Xen,VMware 等都對 ballooning 技術提供支持。其中,KVM 中的 Ballooning 是通過宿主機和客戶機協同來實現的,在宿主機中應該使用 2.6.27 及以上版本的 Linux內核(包括KVM模塊),使用較新的 qemu-kvm(如0.13版本以上),在客戶機中也使用 2.6.27 及以上內核且將“CONFIG_VIRTIO_BALLOON”配置為模塊或編譯到內核。在很多Linux發行版中都已經配置有“CONFIG_VIRTIO_BALLOON=m”,所以用較新的Linux作為客戶機系統,一般不需要額外配置virtio_balloon驅動,使用默認內核配置即可。
 
原理:
  1. KVM 發送請求給 VM 讓其歸還一定數量的內存給KVM。
  2. VM 的 virtio_balloon 驅動接到該請求。
  3. VM 的驅動是客戶機的內存氣球膨脹,氣球中的內存就不能被客戶機使用。
  4. VM 的操作系統歸還氣球中的內存給VMM
  5. KVM 可以將得到的內存分配到任何需要的地方。
  6. KM 也可以將內存返還到客戶機中。

優勢和不足:

 
優勢 不足
  1. ballooning 可以被控制和監控
  2. 對內存的調節很靈活,可多可少。
  3. KVM 可以歸還內存給客戶機,從而緩解其內存壓力。
  1. 需要客戶機安裝驅動
  2. 大量內存被回收時,會降低客戶機的性能。
  3. 目前沒有方便的自動化的機制來管理 ballooning,一般都在 QEMU 的 monitor 中執行命令來實現。
  4. 內存的動態增加或者減少,可能是內存被過度碎片化,從而降低內存使用性能。

在QEMU monitor中,提供了兩個命令查看和設置客戶機內存的大小。

  • (qemu) info balloon    #查看客戶機內存占用量(Balloon信息)
  • (qemu) balloon num   #設置客戶機內存占用量為numMB
使用實例:

 (1)啟動一個虛機,內存為 2048M,啟用 virtio-balloon

(2)通過 vncviewer 進入虛機,查看 pci 設備

(3)看看內存情況,共 2G 內存

(4)進入 QEMU Monitor,調整 balloon 內存為 500M

(5)回到虛機,查看內存,變為 500 M

 2.7 RedHat 的 多隊列 Virtio (multi-queue)

    目前的高端服務器都有多個處理器,虛擬使用的虛擬CPU數目也不斷增加。默認的 virtio-net 不能並行地傳送或者接收網絡包,因為 virtio_net 只有一個TX 和 RX 隊列。而多隊列 virtio-net 提供了一個隨着虛機的虛擬CPU增加而增強網絡性能的方法,通過使得 virtio 可以同時使用多個 virt-queue 隊列。
 
它在以下情況下具有明顯優勢:
  1. 網絡流量非常大
  2. 虛機同時有非常多的網絡連接,包括虛擬機之間的、虛機到主機的、虛機到外部系統的等
  3. virtio 隊列的數目和虛機的虛擬CPU數目相同。這是因為多隊列能夠使得一個隊列獨占一個虛擬CPU。
注意:對隊列 virtio-net 對流入的網絡流工作得非常好,但是對外發的數據流偶爾會降低性能。打開對隊列 virtio 會增加中的吞吐量,這相應地會增加CPU的負擔。 在實際的生產環境中需要做必須的測試后才確定是否使用。
 
在 RedHat 中,要使用多隊列 virtio-net,在虛機的 XML 文件中增加如下配置:
然后在主機上運行下面的命令:
ethtool -L eth0 combined M ( 1 <= M <= N)

2.8 Windows 客戶機的 virtio 前端驅動

Windows 客戶機下的 virtio 前端驅動必須下載后手工安裝。 RedHat Linux  這篇文章 說明了在 Windows 客戶機內安裝virtio 驅動的方法。
 

3. 一些測試數據

3.1 virtio 和 ide 的對比

Virtio半虛擬化驅動的方式可以獲得很好的I/O性能,比純軟件模擬高於4倍多,其性能幾乎可以達到和Native(即非虛擬化環境中的原生系統)差不多的I/O性能。所以,在使用KVM之時,如果宿主機內核和客戶機都支持VirtIO的情況下,一般推薦使用Virtio達到更好的性能。

VirtIO半虛擬化驅動的方式可以獲得很好的IO延遲,從另一個層面驗證了半虛擬化驅動在KVM發揮的性格優勢。 

 
參考文檔:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM