1. 全虛擬化 I/O 設備
1.1 原理

- 客戶機的設備驅動程序發起 I/O 請求操作請求
- KVM 模塊中的 I/O 操作捕獲代碼攔截這次 I/O 請求
- 經過處理后將本次 I/O 請求的信息放到 I/O 共享頁 (sharing page),並通知用戶空間的 QEMU 程序。
- QEMU 程序獲得 I/O 操作的具體信息之后,交由硬件模擬代碼來模擬出本次 I/O 操作。
- 完成之后,QEMU 將結果放回 I/O 共享頁,並通知 KMV 模塊中的 I/O 操作捕獲代碼。
- KVM 模塊的捕獲代碼讀取 I/O 共享頁中的操作結果,並把結果放回客戶機。
1.2 QEMU 模擬網卡的實現
Qemu 純軟件的方式來模擬I/O設備,其中包括經常使用的網卡設備。Guest OS啟動命令中沒有傳入的網絡配置時,QEMU默認分配 rtl8139 類型的虛擬網卡類型,使用的是默認用戶配置模式,這時候由於沒有具體的網絡模式的配置,Guest的網絡功能是有限的。 全虛擬化情況下,KVM虛機可以選擇的網絡模式包括:
- 默認用戶模式(User);
- 基於網橋(Bridge)的模式;
- 基於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的收發包的流程。

如圖中所示,紅色箭頭表示數據報文的入方向,步驟:
- 網絡數據從 Host 上的物理網卡接收,到達網橋;
- 由於 eth0 與 tap1 均加入網橋中,根據二層轉發原則,br0 將數據從 tap1 口轉發出去,即數據由 Tap設備接收;
- Tap 設備通知對應的 fd 數據可讀;
- fd 的讀動作通過 tap 設備的字符設備驅動將數據拷貝到用戶空間,完成數據報文的前端接收。
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 模擬。


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
2.1 virtio 的架構



2.2 Virtio 在 Linux 中的實現
- 前端驅動:客戶機中安裝的驅動程序模塊
- 后端驅動:在 QEMU 中實現,調用主機上的物理設備,或者完全由軟件實現。
- virtio 層:虛擬隊列接口,從概念上連接前端驅動和后端驅動。驅動可以根據需要使用不同數目的隊列。比如 virtio-net 使用兩個隊列,virtio-block只使用一個隊列。該隊列是虛擬的,實際上是使用 virtio-ring 來實現的。
- virtio-ring:實現虛擬隊列的環形緩沖區

- 塊設備(如磁盤)
- 網絡設備
- PCI 設備
- 氣球驅動程序(動態管理客戶機內存使用情況)
- 控制台驅動程序
(1)virtio-net 的原理:
- 多個虛機共享主機網卡 eth0
- QEMU 使用標准的 tun/tap 將虛機的網絡橋接到主機網卡上
- 每個虛機看起來有一個直接連接到主機PCI總線上的私有 virtio 網絡設備
- 需要在虛機里面安裝 virtio驅動
(2)virtio-net 的流程:
- 優點:更高的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 (氣球)技術可以在客戶機運行時動態地調整它所占用的宿主機內存資源,而不需要關閉客戶機。該技術能夠:
- 當宿主機內存緊張時,可以請求客戶機回收利用已分配給客戶機的部分內存,客戶機就會釋放部分空閑內存。若其內存空間不足,可能還會回收部分使用中的內存,可能會將部分內存換到交換分區中。
- 當客戶機內存不足時,也可以讓客戶機的內存氣球壓縮,釋放出內存氣球中的部分內存,讓客戶機使用更多的內存。
- KVM 發送請求給 VM 讓其歸還一定數量的內存給KVM。
- VM 的 virtio_balloon 驅動接到該請求。
- VM 的驅動是客戶機的內存氣球膨脹,氣球中的內存就不能被客戶機使用。
- VM 的操作系統歸還氣球中的內存給VMM
- KVM 可以將得到的內存分配到任何需要的地方。
- KM 也可以將內存返還到客戶機中。
優勢和不足:
優勢 | 不足 |
|
|
在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)

- 網絡流量非常大
- 虛機同時有非常多的網絡連接,包括虛擬機之間的、虛機到主機的、虛機到外部系統的等
- virtio 隊列的數目和虛機的虛擬CPU數目相同。這是因為多隊列能夠使得一個隊列獨占一個虛擬CPU。


ethtool -L eth0 combined M ( 1 <= M <= N)
2.8 Windows 客戶機的 virtio 前端驅動
3. 一些測試數據
3.1 virtio 和 ide 的對比
Virtio半虛擬化驅動的方式可以獲得很好的I/O性能,比純軟件模擬高於4倍多,其性能幾乎可以達到和Native(即非虛擬化環境中的原生系統)差不多的I/O性能。所以,在使用KVM之時,如果宿主機內核和客戶機都支持VirtIO的情況下,一般推薦使用Virtio達到更好的性能。
VirtIO半虛擬化驅動的方式可以獲得很好的IO延遲,從另一個層面驗證了半虛擬化驅動在KVM發揮的性格優勢。
- http://linux.web.cern.ch/linux/centos7/docs/rhel/Red_Hat_Enterprise_Linux-7-Virtualization_Tuning_and_Optimization_Guide-en-US.pdf
- http://toast.djw.org.uk/qemu.html
- KVM 官方文檔
- KVM 虛擬化技術實戰與解析 任永傑、單海濤 著
- RedHat Linux 6 官方文檔
- http://www.slideshare.net 中關於 KVM 的一些文檔
- http://www.linux-kvm.org/page/Multiqueue
- 以及部分來自於網絡,比如 http://smilejay.com/2012/11/use-ballooning-in-kvm/
- http://www.h3c.com/cn/d_201311/804193_30008_0.htm