第一部分 SR-IOV簡介
https://cloud.tencent.com/developer/article/1087112
1.1 SR-IOV簡介
SR-IOV(PCI-SIG Single Root I/O Virtualization and Sharing)是PCI-SIG組織發布的規范。
設計PCI-SIG SR-IOV 規范的目的是:通過為虛擬機提供獨立的內存地址、中斷和DMA流而避免VMM的介入。SR-IOV允許一個PCI設備提供多個VFs。VMM將一個或者多個 VF 分配給一個虛機。一個VF同時只能被分配一個虛機。而虛擬機感知不到這個網卡是被VF的還是普通的物理網卡。
1.2 SR-IOV引入了兩個PCIe的function types
PFs:包括管理SR-IOV功能在內的所有PCIe function。
VFs:一部分輕量級的PCIe function,只能進行必要的數據操作和配置。
1.3 R-IOV工作流程中有三個角色
1.PCIe的SR-IOV機制:提供獨立可配置的多個VFs,每一個VFs具有獨立的PCIe配置空間。
2.VMM:則把VFs分配給虛擬機。
3.VT-x和VT-d:通過硬件輔助技術提供和虛擬機之間的直接DMA數據映射傳輸,跳過VMM的干預。
1.4 SR-IOV原理
下面一幅圖描述了SR-IOV的原理(來自intel《PCI-SIG SR-IOV Prime》):
1.5 SR-IOV的優缺點
SR-IOV相對與軟件模擬IO虛擬化的優點:
1.降低了IO延遲和對CPU的占用,獲得了接近原生的IO性能,因為虛擬機直接使用VFs,沒有了VMM的陷入處理。
2.數據更加安全,因為每個VF屬於一個IOMMU Group,共享IOMMU Group的設備不能分配給不同的虛擬機,而每個IOMMU Group又有獨立的內存。
SR-IOV相對與Device assignment的優點:
沒有了一個PCI設備只能給一個虛擬機的尷尬,SR-IOV下多個虛擬機可通過獨占VFs的方式共享一個PCI設備。
SR-IOV的缺點:
使用了VFs的虛擬機不能在線遷移。
第二部分 KVM熱遷移原理
https://www.ibm.com/developerworks/cn/linux/l-cn-mgrtvm1/index.html 介紹原理
https://www.ibm.com/developerworks/cn/linux/l-cn-mgrtvm2/index.html 實驗(操作qemu執行熱遷移)
https://developers.redhat.com/blog/2015/03/24/live-migrating-qemu-kvm-virtual-machines/
2.1 概述
遷移的前面階段,服務在源主機運行,當遷移進行到一定階段,目的主機已經具備了運行系統的必須資源,經過一個非常短暫的切換,源主機將控制權轉移到目的主機,服務在目的主機上繼續運行。
對於 VM 的內存狀態的遷移,XEN 和 KVM 都采用了主流的的預拷貝(pre-copy)的策略。遷移開始之后,源主機 VM 仍在運行,目的主機 VM 尚未啟動。遷移通過一個循環,將源主機 VM 的內存數據發送至目的主機 VM。循環第一輪發送所有內存頁數據,接下來的每一輪循環發送上一輪預拷貝過程中被 VM 寫過的臟頁內存 dirty pages。直到時機成熟,預拷貝循環結束,進入停機拷貝階段,源主機被掛起,不再有內存更新。最后一輪循環中的臟頁被傳輸至目的主機 VM。
預拷貝機制極大的減少了停機拷貝階段需要傳輸的內存數據量,從而將停機時間大大縮小。【意思是預拷貝不影響vm的在線運行,減少了停機時間】
最右邊部分的圖表是QEMU狀態,整個狀態不涉及遷移過程。但是在遷移開始之前將這個狀態設置正確很重要。在源主機和目的主機上的QEMU設置必須相同,這是通過在兩個主機上使用一條相似的QEMU命令行來實現的。由於QEMU命令行的多種選擇非常難以搞定,我們使用Libvirt替我們選擇正確的。Libvirt可以確保QEMU兩邊程序的遷移設置正確性。
在線遷移分3個階段:
第一個階段:將所有RAM都標記臟
第二個階段:持續不斷發送臟RAM,當達到一些低水印或者條件時停止
第三個階段:停止運行客戶機,將剩余臟RAM,設備狀態轉移過去,在目標主機QEMU上啟動虛擬機
在第二階段代碼,我們會在每個迭代來檢查有多少頁面被客戶機標記臟。會檢查花費多長時間來轉換一個頁面,以便來設定一個預估的網絡帶寬。在這個預估帶寬和當前迭代的臟頁面數量,我們可以計算出花費多久來轉化剩余頁面。如果在可接受或者設置的停機時間限制內,我們過渡到第三階段是沒有問題的。否則我們會繼續停留在第二階段。
QEMU中還有更多的與遷移有關的代碼:有些代碼是用來發送/接受遷移數據:TCP或者UNIX包,本地文件說明符,或者RDMA。也有exec功能,來自QEMU的數據,在被發送到目的地前,會被傳輸到其他進程。這對於傳出數據壓縮,加密都很有用。在目的端,也需要進行解壓縮或者解加密進程。對於UNIX包,fd或者exec-based協議,需要更高層的程序來管理兩端的遷移。Libvirt就是這個程序,我們可以依賴libvirt的能力來控制這個遷移。
2.2 如何判斷”時機成熟“
對於更新速度非常快的內存部分,每次循環過程都會變臟,需要重復 pre-copy,同時也導致循環次數非常多,遷移的時間變長。針對這種情況,KVM 虛擬機建立了三個原則:集中原則,一個循環內的 dirty pages 小於等於 50;不擴散原則, 一個循環內傳輸的 dirty pages 少於新產生的;有限循環原則,循環次數必須少於 30。在實現上,就是采取了以下措施:
- 有限循環:循環次數和效果受到控制,對每輪 pre-copy 的效果進行計算,若 pre-copy 對於減少不一致內存數量的效果不顯著,或者循環次數超過了上限,循環將中止,進入停機拷貝階段。
- 在被遷移 VM 的內核設置一個內存訪問的監控模塊。在內存 pre-copy 過程中,VM 的一個進程在一個被調度運行的期間,被限制最多執行 40 次內存寫操作。這個措施直接限制了 pre-copy 過程中內存變臟的速度,其代價是對 VM 上的進程運行進行了一定的限制。【這個模塊是要改guest OS嗎?】
2.3 遷移過程詳解
(1)系統驗證目標服務器的存儲器和網絡設置是否正確,並預保留目標服務器虛擬機的資源。
圖 1. 源服務器和目標服務器簡圖
(2)當虛擬機還在源服務器上運轉時,第一個循環內將全部內存鏡像復制到目標服務器上。在這個過程中,KVM 依然會監視內存的任何變化。
圖 2. 內存鏡像復制示意圖
(3)以后的循環中,檢查上一個循環中內存是否發生了變化。 假如發生了變化,那么 VMM 會將發生變化的內存頁即 dirty pages 重新復制到目標服務器中,並覆蓋掉先前的內存頁。在這個階段,VMM 依然會繼續監視內存的變化情況。
圖 3. 進行有變化的內存復制
(4)VMM 會持續這樣的內存復制循環。隨着循環次數的增加,所需要復制的 dirty pages 就會明顯減少,而復制所耗費的時間就會逐漸變短,那么內存就有可能沒有足夠的時間發生變化。最后,當源服務器與目標服務器之間的差異達到一定標准時,內存復制操作才會結束,同時暫停源系統。
圖 4. 所需復制的數據在減少
(5)在源系統和目標系統都停機的情況下,將最后一個循環的 dirty-pages 和源系統設備的工作狀態復制到目標服務器。
圖 5. 狀態信息的復制
(6)然后,將存儲從源系統上解鎖,並鎖定在目標系統上。啟動目標服務器,並與存儲資源和網絡資源相連接。
圖 6. 停止源服務器,啟動目標服務器
第三部分 passthrough與SR-IOV區別、vhost和vhost-user等
https://www.cnblogs.com/sammyliu/p/4548194.html
http://virtual.51cto.com/art/201801/563894.htm
https://blog.csdn.net/qq_15437629/article/details/77899905
http://blog.vmsplice.net/2011/09/qemu-internals-vhost-architecture.html
https://spdk.io/doc/vhost_processing.html
3.1 Passthrough
設備直接分配 (Device assignment)也稱為 Device Pass-Through。
先簡單看看PCI 和 PCI-E 的區別(AMD CPU):
(簡單點看,PCI 卡的性能沒有 PCI-E 高,因為 PCI-E 是直接連在 IOMMU 上,而 PCI 卡是連在一個 IO Hub 上。)
IOMMU = Input/Output Memory Management Unit
主要的 PCI 設備類型:
- Network cards (wired or wireless)
- SCSI adapters
- Bus controllers: USB, PCMCIA, I2C, FireWire, IDE
- Graphics and video cards
- Sound cards
- 好處:在執行 I/O 操作時大量減少甚至避免 VM-Exit 陷入到 Hypervisor 中,極大地提高了性能,可以達到幾乎和原生系統一樣的性能。VT-d 克服了 virtio 兼容性不好和 CPU 使用頻率較高的問題。
- 不足:(1)一台服務器主板上的空間比較有限,因此允許添加的 PCI 和 PCI-E 設備是有限的。大量使用 VT-d 獨立分配設備給客戶機,讓硬件設備數量增加,這會增加硬件投資成本。(2)對於使用 VT-d 直接分配了設備的客戶機,其動態遷移功能將受限,不過也可以使用熱插拔或者libvirt 工具等方式來緩解這個問題。
- 不足的解決方案:(1)在一台物理宿主機上,僅少數 I/O 如網絡性能要求較高的客戶機使用 VT-d直接分配設備,其他的使用純模擬或者 virtio 已達到多個客戶機共享同一個設備的目的 (2)對於網絡I/O的解決辦法,可以選擇 SR-IOV 是一個網卡產生多個獨立的虛擬網卡,將每個虛擬網卡分配個一個客戶機使用。

硬盤直接分配:
- 一般 SATA 或者 SAS 等類型的硬盤的控制器都是直接接入到 PCI 或者 PCI-E 總線的,所以也可以將硬盤作為普通的PCI設備直接分配個客戶機。需要注意的是,當分配硬盤時,實際上將其控制器作為一個整體分配到客戶機中,因此需要在硬件平台上至少有另兩個或者多個SATA或者 SAS控制器。
3.2 Passthrough分配示例:
准備工作:
(1)在 BIOS 中打開 Intel VT-d
(2)在 Linux 內核中啟用 PCI Pass-through
添加 intel_iommu=on 到 /boot/grub/grub.conf 文件中。(在我的 RedHat Linux 6上,該文件是 /boot/grub.conf)
(3)重啟系統,使得配置生效
實際分配:
(1)使用 lspci -nn 命令找到待分配的 PCI 設備。這里以一個 FC 卡為例:
使用 lspci 命令得到的 PCI 數字的含義,以后使用 libvirt API 分配設備時會用到:
(2)使用 virsh nodedev-list 命令找到該設備的 PCI 編號
(3)將設備從主機上解除
(4)使用 virt-manager 將設備直接分配給一個啟動了的虛擬機
3.3 各種設備虛擬化方式的比較【注意:什么是vhost???】
3.4 IO設備的虛擬化方式
3.4.1 全虛擬化下vm的IO路徑
(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操作已經完成。
3.4.2 半虛擬化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。
IBM在2005年提出了virtio, 虛擬機中的半虛擬化前端驅動和主機上的后端服務簡單的使用virtqueue共享隊列交換數據,大幅的減少了e1000模擬時復雜的io操作,從而可以較大程度的提升虛擬網絡性能。
guest使用virtio driver將請求發送給virtio-backend。
圖中描述了virtio的io路徑: guest發出中斷信號退出kvm,從kvm退出到用戶空間的qemu進程。然后由qemu開始對tap設備進行讀寫。 可以看到這里從用戶態進入內核,再從內核切換到用戶態,進行了2次切換。
virtio的io路徑:guest設置好tx→kick host→guest陷出到kvm→kvm從內核切換到用戶態的qemu進程→qemu將tx數據投遞到tap設備
3.4.3 vhost和vhost-user
為了解決virio的IO路徑太長的問題,vhost產生了。它是位於host kernel的一個模塊,用於和guest直接通信,所以數據交換就在guest和host kernel間進行,減少了上下文的切換。
vhost相對與virto架構,把virtio驅動后端驅動從用戶態放到了內核態中(vhost的內核模塊充當virtiO后端驅動),在內核中加入了vhost-net.ko模塊,使得對網絡數據可以在內核態得到處理。
guest發出中斷信號退出kvm,kvm直接和vhost-net.ko通信,然后由vhost-net.ko訪問tap設備。 這樣網絡數據只需要經過從用戶態到內核態的一次切換,就可以完成數據的傳輸。大大提高了虛擬網卡的性能。
路徑:guest設置好tx→kick host→guest陷出到kvm→vhost-net將tx數據投遞到tap設備
vhost-user和vhost類似,只是使用一個用戶態進程vhost-user代替了內核中的vhost模塊。
vhost-user進程和Guset之間時通過共享內存的方式進行數據操作。vhost-user相對與vhost架構,把virtio驅動后端驅動從內核態又放回到了用戶態中(vhost-user進程充當virtiO后端驅動)。
它將網絡數據放入用戶態處理將可以得到更靈活的形式:
路徑:guest設置好tx→kick host→guest陷出到kvm→kvm將通知vhost-backend→vhost-backend將tx數據直接發送到nic設備
vhost-backend從原來kernel中的vhost-net 變成了用戶空間的snabbswitch,snabbswitch直接接管物理網卡的驅動,從而直接控制網絡信息的輸入輸出。snabbswitch主要使用了下面的技術來提高性能:
- 采用了大頁來作為host和vm之間通信的內存空間
- 用戶態操作網卡,使用類似於netmap的zero copy技術來加速對物理設備的訪問
- 使用numa技術,加快中斷響應速率
值得一提的是使用snabbswitch后,不用再使用原來的tap設備模擬的網卡。
使用vhost-user技術,從虛擬機到host上實現了數據的zero copy(通過大頁共享),host到nic的zero copy(snabbswitch實現的驅動),能進一步加快數據的傳輸。
DPDK便是一個在用戶態可以直接操作物理網卡的庫函數,它和vhost-user結合便可以實現類似於snabb switch一樣性能強勁的用戶態交換機了。
【有了vhost-user,DPDK和SPDK(storage performance xx)等加速框架就得以實現了】