字節(jié)跳動提出KVM內(nèi)核熱升級方案,效率提升5.25倍!
背景
作為云計算最重要的底層基礎(chǔ)之一,KVM 虛擬化軟件在現(xiàn)代的數(shù)據(jù)中心中應(yīng)用非常廣泛。基于 KVM 的 hypervisor 包括了構(gòu)成宿主機的軟硬件,共同為虛擬機中的應(yīng)用程序提供高性能的 CPU、內(nèi)存和 IO 設(shè)備等資源。在大規(guī)模部署的生產(chǎn)環(huán)境中,作為云服務(wù)提供商(Cloud Service Provider),如何從技術(shù)上保證軟硬件的可運維性,一直是大家重點關(guān)注的問題。
為了給用戶提供穩(wěn)定、安全、高效并且功能豐富的云資源,IaaS 的底層軟件必須能夠支撐軟硬件的各種運維需求。例如,在偶然出現(xiàn)一些難以避免的硬件故障時,需要能夠把虛擬機及時熱遷移到健康的宿主機;或者,在軟件安全漏洞或功能缺陷被修復(fù)后,能夠通過熱升級,及時部署上線到生產(chǎn)環(huán)境中。
然而實現(xiàn)用戶無感知地?zé)徇w移和熱升級,卻是一個復(fù)雜的系統(tǒng)工程問題。因為 KVM 虛擬化涉及眾多不同層次的組件、諸多特性和靈活可選的組合方式,其中不乏一些非常復(fù)雜的軟硬件技術(shù)例如 SR-IOV、Linux內(nèi)核、QEMU、DPDK、KubeVirt 或者 OpenStack 等,系統(tǒng)總體架構(gòu)復(fù)雜度很高。而且這些軟硬件模塊各自都有復(fù)雜的接口和內(nèi)部狀態(tài),在不影響虛擬機正常運行的情況下,要做到宿主機軟件的熱升級和熱遷移,還需要做一些針對性的設(shè)計或改造。同時,作為云計算底座的一部分,它們也需要緊密地配合才能完成預(yù)期的功能。特別是對于內(nèi)部狀態(tài)處理能力要求非常高的熱升級功能,更需要深入、全面的打通。
目前,在各個開源社區(qū)(如 Linux,QEMU,CloudHypervisor 等)和各大云計算公司,都在積極地嘗試對 KVM 的熱升級支持進行研發(fā),也是歷年各大技術(shù)峰會的一個重要研討主題。字節(jié)跳動技術(shù)團隊從實際場景出發(fā),相應(yīng)地對熱升級問題進行了深入分析,與開源社區(qū)緊密合作,從多個角度做出了深度探索并取得了進展。
在今年 9 月份舉行的虛擬化領(lǐng)域全球技術(shù)峰會 KVM Forum上,字節(jié)跳動系統(tǒng)技術(shù)與工程團隊 (System Technologies&Engineering,簡稱STE團隊 )公布了相關(guān)的技術(shù)成果:首次提出一種在KVM熱升級場景中透明支持 PCI 直通設(shè)備的方案,能夠顯著降低內(nèi)核熱升級的實現(xiàn)成本 。通過對 host 內(nèi)核和 QEMU 的擴展和改進,可以做到不依賴于特定硬件修改或者 guest 配合的熱升級,支持 PCI 直通設(shè)備。同時,在性能方面,也通過深入的分析和優(yōu)化,將一次內(nèi)核熱升級所需的最少時間(downtime)從 1000ms 降低至 160ms,效率提升 5.25 倍 。
本文將整理回顧 KVM Forum 大會中分享的主要技術(shù)方案,以饗讀者。
KVM Forum 會議演講視頻鏈接:
Preserving IOMMU States During Kexec Reboot:
https://share.weiyun.com/Mz3Wk6v8
IOMMU狀態(tài)保持
PCI 設(shè)備直通在當(dāng)前數(shù)據(jù)中心的 KVM 虛擬化場景中廣泛應(yīng)用,能夠為虛擬機中的應(yīng)用提供高性能的 IO 設(shè)備。同時,直通設(shè)備的使用也為云計算底層軟件設(shè)施的運維帶來了一些復(fù)雜度。
其中,對熱升級和熱遷移的兼容性是 PCI 直通設(shè)備的一大難點。這是因為熱升級或熱遷移操作依賴于對虛擬機狀態(tài)的提取、保持、傳輸?shù)炔僮鳎?PCI 直通設(shè)備的狀態(tài)數(shù)據(jù)對于宿主機側(cè)的 hypervisor 是不透明的。因此在 IaaS 的實踐中,往往需要對使用了直通設(shè)備的虛擬機進行特殊處理。例如,通過定制的 SR-IOV 硬件,實現(xiàn) PF 管理 VF 狀態(tài)的邏輯;或者在虛擬機中運行特殊的驅(qū)動程序和 agent 進程,通過 guest 在過程中的協(xié)同配合來完成熱遷移或熱升級操作。
這些方法可以在一定程度上解決 PCI 直通設(shè)備的運維難題,但是帶來了更高的研發(fā)成本、軟件和配置的復(fù)雜度,也有可能會犧牲用戶體驗和 IO 性能。
技術(shù)方案調(diào)研
在 KVM 中對 PCI 設(shè)備的直通需要通過 VFIO-PCI 接口來完成。VFIO-PCI 是 Linux 內(nèi)核對 IOMMU 和 PCI 底層邏輯的抽象封裝 API,提供給運行在用戶態(tài)的 QEMU 或者其它 VMM(Virtual Machine Manager)軟件來配置虛擬設(shè)備的 IO 映射關(guān)系,從而允許虛擬機內(nèi)核驅(qū)動直接訪問硬件資源,以達到較高的 IO 效率。
在熱升級過程中,虛擬機的運行狀態(tài)需要被穩(wěn)定地保持在升級之前的狀態(tài),其中包括虛擬機的 CPU 狀態(tài)(寄存器里的數(shù)據(jù)等)、內(nèi)存數(shù)據(jù)、虛擬設(shè)備的接口狀態(tài)和內(nèi)部狀態(tài)等。對于 PCI 直通設(shè)備來說,有2個思路:
設(shè)法提取設(shè)備的狀態(tài)數(shù)據(jù),備份在預(yù)先設(shè)計好的位置(如預(yù)留的內(nèi)存或者磁盤),然后在熱升級結(jié)束之前,從備份中恢復(fù)。提取備份的過程,一般稱之為序列化;從數(shù)據(jù)中恢復(fù)狀態(tài)的過程稱之為反序列化。
不提取設(shè)備狀態(tài)數(shù)據(jù),并在熱升級過程中完全不改變設(shè)備狀態(tài)。熱升級完成后,虛擬機繼續(xù)訪問這個硬件設(shè)備。
前一種思路已經(jīng)被證明是可行的方案,并且在某些較新的硬件中已實現(xiàn),它的優(yōu)點是不僅可以用來熱升級,也可以用來熱遷移。在熱遷移過程中,虛擬機會被轉(zhuǎn)移到不同的物理機上,也就不可能再使用同一個設(shè)備。但是,這個方式的缺點是必須有硬件支持,同時因為存在序列化、反序列化的操作,完成熱升級所需時間較長。
我們對第二種情況進行調(diào)研和實驗后發(fā)現(xiàn),通過對 Linux 內(nèi)核進行一些局部的修改,在 Intel IOMMU 上可以實現(xiàn)在熱升級過程中,設(shè)備狀態(tài)的完全隔離和保護,從而得到一個 PCI 透傳設(shè)備的熱升級通用支持方法。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)? ? ?


解決方案
本文提出的方案主要包括三個部分。
改進一**:通過在 hypervisor 中引入必要的靜態(tài)頁面分配,保證 kexec 重啟過程中的狀態(tài)保持。
靜態(tài)分配主要有用戶態(tài)和內(nèi)核態(tài)兩部分工作。其中,用戶態(tài)的工作方式為:
虛擬機的 RAM 使用 memmap 方式分配,在 host 側(cè)使用 DAX 的形式管理。memmap 是一個內(nèi)核參數(shù),可以為物理內(nèi)存分配不同的屬性。其中 E820 type 12是一個 NVDIMM 類型(例如 memmap = 2G!6G)。
這個類型的物理頁,將不再被內(nèi)核動態(tài)管理,而是作為“非易失性內(nèi)存”來看待。在啟動后,我們可以通過創(chuàng)建一個 DevDax 字符設(shè)備,mmap 到 QEMU 的地址空間。
DevDax 的創(chuàng)建可以使用系統(tǒng)調(diào)用,也可以用 ndctl 命令:
該命令會創(chuàng)建一個類似 /dev/dax1.0 的字符設(shè)備。這個字符設(shè)備提供一個支持DAX(Linux內(nèi)核提供的直接物理地址訪問機制)的 mmap 接口,可以直接將物理內(nèi)存映射到 QEMU 用戶態(tài)。QEMU 命令行參數(shù)如下:
而后 QEMU 會通過 KVM 接口把這段預(yù)留內(nèi)存用于填充 EPT 頁表。
改進二:內(nèi)核態(tài)的靜態(tài)分配實現(xiàn)需要通過一個內(nèi)核補丁來實現(xiàn)
我們在內(nèi)核中引入了一個新的物理頁管理器 KRAM,為其它模塊提供2個分配頁的函數(shù)接口。這兩個接口的主要目的是提供靜態(tài)物理頁給硬件相關(guān)模塊。
kram_get_fixed_page(area, index)
kram_alloc_page()
在 E820 的 enum 中定義新的 type 用以預(yù)留物理頁給 KRAM:memmap=:
在 Intel 的 IOMMU 驅(qū)動模塊中,使用 kram 接口來分配 root page 和 DMAR page。包括iommu_alloc_root_entry和alloc_pgtable_page等函數(shù)中,將原本的alloc_pgtable_page替換成對 KRAM 模塊的調(diào)用。
改進三:對VFIO設(shè)備簡化,保證硬件狀態(tài)不被干擾
在VFIO-PCI相關(guān)系統(tǒng)調(diào)用(VFIO_GROUP_SET_FLAGS)中,我們加入了一個新的標(biāo)志位,用以在 QEMU 熱升級過程中,跳過對VFIO-PCI設(shè)備的初始化和重置。
第二、三部分的相關(guān)代碼將會在后續(xù)開源。
POC驗證
目前我們在 QEMU 模擬環(huán)境中對上面的方案進行了實驗。借助 KVM 在 Intel CPU上的嵌套虛擬化支持,和 QEMU 對虛擬 IOMMU 的支持,可以很快的啟動一個測試環(huán)境:
上面的命令啟動的嵌套虛擬化的 L1,運行的是增加了 VFIO-PCI 熱升級的內(nèi)核。對 L1里安裝的 QEMU 同樣也加入了 CPR(Checkpoint Restore)和 VFIO-PCI 的擴展調(diào)用。
使用 VFIO-PCI 我們分配上面的虛擬 e1000e 網(wǎng)卡給 L2:
然后,通過 cpr-save -> kexec -> 啟動qemu -> restore 的流程來熱升級整個 L1。
在測試過程中采集到的時間記錄如下:

編輯切換為居中
從暫停虛擬機,到重啟以后虛擬機恢復(fù)運行并在虛擬網(wǎng)絡(luò)上繼續(xù)發(fā)包,一共經(jīng)過了 159ms。虛擬 e1000 網(wǎng)卡在這個過程中沒有被 reset,始終保持運行狀態(tài)。也就是說從外部或者應(yīng)用視角來看,因宿主機熱升級而導(dǎo)致的總響應(yīng)時間,僅僅增加了不到 160ms 的時長,并且由于網(wǎng)卡的 rx 隊列始終可用,在流量較低的情況下,也不會導(dǎo)致丟包和重傳。相比之下,如果用內(nèi)核和 QEMU 的主線版本來執(zhí)行上面的流程,可以采用 savevm 到磁盤后 kexec 重啟并 loadvm 的步驟。但是這樣不僅不能支持VFIO-PCI設(shè)備,也會因為缺少各種優(yōu)化(如:savevm/loadvm 需要復(fù)制虛擬機內(nèi)存),產(chǎn)生 1000ms 以上的 downtime 延遲。
結(jié)論
在使用 VFIO-PCI 透傳設(shè)備的宿主機上,部署了具有上述改進的 host 內(nèi)核和 QEMU 等程序。在測試中,基于 QEMU 通用的 checkpointing and recovery(CPR)框架,我們現(xiàn)可以支持低損耗的 host 內(nèi)核熱升級動作。從暫停虛擬機,到重啟進入新內(nèi)核并繼續(xù)執(zhí)行虛擬機,整個過程可在 160ms 左右完成。
此技術(shù)方案可被應(yīng)用在公有云和私有云的 IaaS 業(yè)務(wù)場景,具有很高的實用價值,能夠顯著降低運維成本,提高云的安全性,并優(yōu)化運維過程中的虛擬機運行性能和客戶體驗。字節(jié)跳動系統(tǒng)與技術(shù)工程團隊將會繼續(xù)優(yōu)化 Linux 內(nèi)核和虛擬化軟件,為數(shù)據(jù)中心持續(xù)提供安全、穩(wěn)定、高效運行的系統(tǒng)軟件。
此外,在 Virtio 設(shè)備標(biāo)準(zhǔn),QEMU 熱升級,Linux 啟動時間,io_uring,kexec 等方面,團隊也進行了深入的研究和優(yōu)化。我們將會在本文和后續(xù)文章中持續(xù)分享相關(guān)技術(shù)和最新進展。
原文作者:字節(jié)跳動SYS Tech
