實(shí)時(shí)虛擬化聽(tīng)起來(lái)有點(diǎn)矛盾,但是它確實(shí)是有用的(在某些條件下),并且為 Linux 內(nèi)核的靈活性又提供了一個(gè)強(qiáng)有力的證明。KVM2015 論壇的前兩個(gè)演講就詳細(xì)的討論了實(shí)時(shí)虛擬化。第一個(gè)演講者是 Rik van Riel,他講解了實(shí)時(shí)虛擬化的內(nèi)核部分的工作(Youtube視頻和幻燈片)。而第二個(gè)演講者 Jan Kiszka 則解釋了如何配置主機(jī)以及如何管理實(shí)時(shí)虛擬機(jī)(Youtube視頻和幻燈片)。我們這篇文章就采取了他們兩人的意見(jiàn),首先是 Van Riel 的想法。
PREEMPT_RT 內(nèi)核
實(shí)時(shí)的重點(diǎn)是準(zhǔn)確性,精確性,而不是速度。實(shí)時(shí)工作是那些沒(méi)有及時(shí)處理工作就會(huì)致命的工作,例如電信設(shè)備里的壞音,股票交易中的機(jī)會(huì)錯(cuò)失,航空機(jī)械中的火箭爆炸。這些應(yīng)用的特點(diǎn)是在一秒鐘可能會(huì)有上千個(gè)這樣的關(guān)鍵點(diǎn),他們?cè)试S的最慢響應(yīng)時(shí)間可能小到幾毫秒,并且 99.999% 的這些關(guān)鍵點(diǎn)工作都要被即時(shí)處理,如果沒(méi)有被及時(shí)處理的話... (想想上面的火箭爆炸吧),總之要全部及時(shí)的處理好。速度是重要的,但是要一直保證這種低延遲會(huì)帶來(lái)另一個(gè)問(wèn)題,那就是產(chǎn)出下降。
幾乎每一個(gè)潛在的系統(tǒng)因素都來(lái)自于內(nèi)核。比如,某個(gè)驅(qū)動(dòng)程序可能會(huì)關(guān)閉中斷而阻斷高優(yōu)先級(jí)的程序的調(diào)度。非實(shí)時(shí)內(nèi)核中的自旋鎖也是另外一個(gè)潛在的原因,因?yàn)?linux 在持有自旋鎖的同時(shí)不能進(jìn)行 schedule() 調(diào)度。這些問(wèn)題可以通過(guò)運(yùn)行 PREEMPT_RT(實(shí)時(shí)內(nèi)核補(bǔ)丁集)構(gòu)建的內(nèi)核控制。除了臨界區(qū)代碼,一個(gè) PREEMPT_RT 內(nèi)核致力于使 linux 的每一部分都是可搶占的。
大多數(shù)的修改要求已經(jīng)被并入 linus 的內(nèi)核結(jié)構(gòu)中:搶占式內(nèi)核支持,優(yōu)先級(jí)繼承,高分辨率定時(shí)器,線程中斷處置支持,自旋鎖元注解和 NO_HZ_FULL 模式。雖然 PREEMPT_RT 補(bǔ)丁很大,但和過(guò)去相比已經(jīng)優(yōu)化了很多。目前應(yīng)該解決的主要三件事是:把 non-raw 自旋鎖轉(zhuǎn)為優(yōu)先級(jí)繼承互斥鎖,把中斷處理真正放在線程中運(yùn)行以便實(shí)時(shí)任務(wù)可以搶占他們,和支持搶占的 RCU(Read-Copy Update,讀取-復(fù)制更新)實(shí)現(xiàn)。
遺留的主要問(wèn)題在固件當(dāng)中。x86的系統(tǒng)管理中斷(SMIs)關(guān)心諸如風(fēng)扇轉(zhuǎn)速等事情。SMIs 不能夠被操作系統(tǒng)阻塞,極端情況下會(huì)消耗數(shù)毫秒的時(shí)間。在此期間,操作系統(tǒng)完全被阻塞,除了購(gòu)買(mǎi)良好的硬件之外,別無(wú)它法。內(nèi)核模塊 hwlatdetect 可以用來(lái)檢測(cè)該問(wèn)題,其阻塞一個(gè) CPU 上的中斷,尋找異常的延時(shí)峰值,并用特殊模塊寄存器(MSRs)將該峰值關(guān)聯(lián)到 SMIs 之上。
實(shí)時(shí)虛擬化,真的嗎?
當(dāng)前,實(shí)時(shí)虛擬化聽(tīng)起來(lái)可能難以置信,但確實(shí)可以。當(dāng)然,仍有諸多問(wèn)題存在:例如,虛擬機(jī)(VM)中任務(wù)的優(yōu)先級(jí)和客戶機(jī)中鎖的持有者在主機(jī)中均不可見(jiàn)。這限制了調(diào)度器的靈活性,并阻止了優(yōu)先級(jí)集成。因此,所有虛擬 CPU(VCPU)被置于非常高的優(yōu)先級(jí)。僅僅內(nèi)核軟中斷有更高的優(yōu)先級(jí),因此其向虛擬 CPU 傳遞中斷指令。為了避免讓主機(jī)處于饑餓狀態(tài),系統(tǒng)必須在運(yùn)行系統(tǒng)任務(wù)的 CPU 和運(yùn)行實(shí)時(shí)客戶機(jī)的 CPU 間分區(qū)(使用 ioslcpus 和 nohz_fulkernel 命令行參數(shù)進(jìn)行標(biāo)記)。客戶機(jī)必須以相同的方式在 VCPU 和運(yùn)行普通任務(wù)的 CPU 間進(jìn)行分區(qū)。后者可能會(huì)偶發(fā)性的退出到主機(jī)的用戶態(tài),這可能會(huì)比較長(zhǎng)(非常像裸機(jī)狀態(tài)的SMI),并且阻止客戶機(jī)的調(diào)度。
因此,虛擬化的實(shí)時(shí)客戶機(jī)比在裸機(jī)上的同樣工作負(fù)載要使用更多的資源,而且這些資源必須專用于特定客戶機(jī)。但是,這是可以接受的代價(jià),以支持虛擬化提供的改善的隔離性,可管理性和硬件兼容性。此外,最近的每一代處理器在一個(gè) CPU 插槽里有越來(lái)越多的內(nèi)核可用;摩爾定律看上去在彌補(bǔ)這個(gè)問(wèn)題,至少目前是這樣。
一旦實(shí)時(shí) KVM 設(shè)計(jì)如上實(shí)現(xiàn)出來(lái),剩下的部分就是修復(fù) bug。許多修復(fù)要么是針對(duì) KVM 的,要么是針對(duì) PREEMPT_RT 的,所以它們將有利于所有的實(shí)時(shí)用戶和所有虛擬化用戶。例如,RCU 被改為有客戶機(jī)運(yùn)行時(shí)的擴(kuò)展靜默狀態(tài)。擴(kuò)展了 NOHZ_FULL 的支持,當(dāng)運(yùn)行 SCHED_FIFO(實(shí)時(shí))任務(wù)時(shí)來(lái)完全禁用定時(shí)器時(shí)鐘。在這種情況下,由于更高級(jí)別的任務(wù)已經(jīng)搶先,此任務(wù)不會(huì)被重新調(diào)度,所以并不需要計(jì)時(shí)器時(shí)鐘。加入了一些設(shè)置點(diǎn)來(lái)禁用能引入延遲(比如從宿主機(jī)到客戶機(jī)的時(shí)間同步)的不必要 KVM 功能;這會(huì)占用幾微秒時(shí)間,解決方法就是簡(jiǎn)單地在客戶機(jī)運(yùn)行 ntpd。
虛擬化的開(kāi)支可以通過(guò)使用 PREEMPT_RT 的"簡(jiǎn)單等待隊(duì)列"而不是全功能的 Linux 等待隊(duì)列加以限制。這只會(huì)占用有限時(shí)間的鎖,所以操作的長(zhǎng)度同樣是有限的(中斷處理程序經(jīng)常需要喚醒,所以它們的消耗會(huì)直接影響延遲)。將簡(jiǎn)單等待隊(duì)列合并到主流內(nèi)核的事正在被討論。
另一個(gè)技巧就是稍微提前一點(diǎn)調(diào)度 KVM 的定時(shí)器,這樣就可以抵消注入虛擬中斷時(shí)的消耗。虛擬層將中斷傳遞給客戶機(jī)需要幾個(gè)微秒,KVM 核心模塊中有一個(gè)參數(shù)允許基于客戶機(jī)測(cè)得的延遲進(jìn)行微調(diào)。
最后,新的處理器技術(shù)也有一些幫助。下面的案例是 Intel 的"CacheAllocation Technology"(CAT),這在一些 Haswell CPU 上可以使用。從 DRAM 和 TLB 中加載數(shù)據(jù)未命中結(jié)合起來(lái)的消耗可以導(dǎo)致一個(gè)單點(diǎn)未緩存環(huán)境,這將導(dǎo)致聯(lián)合延遲高達(dá) 50 微秒。CAT 允許對(duì)指定的應(yīng)用保留部分緩存,以防止一個(gè)工作負(fù)載將另一個(gè)工作負(fù)載驅(qū)逐出緩存,而且它使用一個(gè)基于控制組的接口完美進(jìn)行控制。但是,這個(gè)補(bǔ)丁還沒(méi)有納入 Linux 中。
使用反復(fù)測(cè)試得出的結(jié)果出乎意料的好。純物理延遲小于 2 微秒,盡管 KVM 測(cè)量的結(jié)果為 6 毫秒,但任然是一個(gè)很好的結(jié)果。為了達(dá)到這些數(shù)字,系統(tǒng)需要仔細(xì)地設(shè)置以避免所有高延遲的系統(tǒng)操作:沒(méi)有 CPU 變頻,沒(méi)有 CPU 熱插拔,不進(jìn)行內(nèi)核模塊加載或卸載,同時(shí)也沒(méi)有 swapping。除非實(shí)時(shí)輔助程序外,應(yīng)用也進(jìn)行了調(diào)整,以避免使用慢速的設(shè)備(如:硬盤(pán)或音響設(shè)備)。所以,部署實(shí)時(shí) KVM 需要對(duì)系統(tǒng)和工作負(fù)載有深入的了解(例如,確保時(shí)間戳計(jì)數(shù)器的穩(wěn)定,使系統(tǒng)不會(huì)回退到其它的時(shí)鐘源)。隨著人們更多地使用實(shí)時(shí) KVM,一些新的瓶頸將會(huì)被發(fā)現(xiàn),但是內(nèi)核方面的工作大體上進(jìn)行良好。
"我可以在我的云上使用它嗎?"
在這一點(diǎn)上,Van Riel 將舞臺(tái)留給了 Kiszka,Kiszka 將會(huì)對(duì)主機(jī)配置進(jìn)行更多地討論,包括怎樣自動(dòng)化,怎樣使用 libvirt 和 OpenStack 管理系統(tǒng)。
Kiszka 是一個(gè)長(zhǎng)期的 KVM 貢獻(xiàn)者,他供職于西門(mén)子。在許多年前他開(kāi)始使用 KVM,并解決了硬件兼容性問(wèn)題這是一個(gè)遺留的軟件問(wèn)題 [PDF]。他已經(jīng)研究實(shí)時(shí)KVM [YouTube] 許多年,人們現(xiàn)在會(huì)問(wèn):“我可以把它部署在我的云上么?”
答案是“可以”,但是也有一些限制。當(dāng)然這不是公有云。為生產(chǎn)做實(shí)時(shí)控制不是很順利,那是因?yàn)槟阈枰獜囊恍?shù)據(jù)中心做 I/O 很遠(yuǎn)。“云”這里指的是私有云,里面的虛擬機(jī)和進(jìn)程是通過(guò)快速以太網(wǎng)連接的。云環(huán)境下還有許多特性,因?yàn)樗麄儾惶峁┐_定的延遲。舉例來(lái)說(shuō),實(shí)時(shí)路徑不能使用磁盤(pán)或動(dòng)態(tài)遷移,但是這通常不是個(gè)問(wèn)題。
Van Riel 解釋說(shuō),基本的配置已經(jīng)不滿足需要,首先要看的就是網(wǎng)絡(luò)。許多 QEUM 仍然是通過(guò)“大 QEMU 鎖(big QEMU lock)”來(lái)保證的,設(shè)備透?jìng)饕呀?jīng)有延遲問(wèn)題。不過(guò)在一些方面正取得進(jìn)展,比如,它已經(jīng)可以能讓準(zhǔn)虛擬化設(shè)備(virtio-net)和 non-QEMU 后端在一起使用。
KVM 提供了兩個(gè)這樣 virtio-net 的后端,vhost-net 和 vhost-user。Vhost-net 位于內(nèi)核,在虛擬機(jī)上,它從 Linux 網(wǎng)絡(luò)棧的 virtio-net 設(shè)備上連出一個(gè) TAP 設(shè)備。他們都不接受延遲。Vhost-user 與之相反,允許任何用戶空間進(jìn)程提供網(wǎng)絡(luò),并可以與專業(yè)的網(wǎng)絡(luò)庫(kù)一起使用。
以具有實(shí)時(shí)能力網(wǎng)絡(luò)庫(kù)包括數(shù)據(jù)平臺(tái)開(kāi)發(fā)套件(DPDK)或者 SnabbSwitch 為例。這些棧是替代輪詢策略的選擇;這減少了大量的信號(hào)和事件,作為結(jié)果它也會(huì)導(dǎo)致延遲。Kiszka 設(shè)置使用 DPDK 作為 vhost-user 客戶端;當(dāng)然,其運(yùn)行在一個(gè)優(yōu)先級(jí)。為客戶提供及時(shí)的 vcpu 中斷,它必須比 VCPU 線程放置在一個(gè)更高的優(yōu)先級(jí)上。
Kiszka 的應(yīng)用程序沒(méi)有高的包率,所以一個(gè)物理 CPU 足以運(yùn)行所有網(wǎng)絡(luò)接口系統(tǒng)的切換;更苛刻的應(yīng)用程序可能需要為每個(gè)接口提供一個(gè)物理 CPU。
在實(shí)驗(yàn)室里,實(shí)時(shí)虛擬化成型后,轉(zhuǎn)移它們到數(shù)據(jù)中心需要一些額外的工作。成百上千的虛擬機(jī)和大量的異構(gòu)網(wǎng)絡(luò),它們中的一些是實(shí)時(shí)的,另外一些不是,這需要管理和靈活計(jì)費(fèi)。實(shí)現(xiàn)這種需求需要一個(gè)云管理堆疊,諸如:OpenStack 就是一個(gè)被選擇出來(lái)和可擴(kuò)展的,具有實(shí)時(shí)能力的平臺(tái)。它參考的架構(gòu)包含(自底向上):PREEMPT_RT 內(nèi)核,QEMU(在這里客戶機(jī)不是實(shí)時(shí)的,這需要設(shè)置 vhost-user 開(kāi)關(guān)),基于 DPDK 的開(kāi)關(guān),libvirt,和 OpenStack。每一臺(tái)主機(jī),或者說(shuō)“計(jì)算節(jié)點(diǎn)”,被設(shè)定為獨(dú)立的物理 CPU,這解釋了上半部分的內(nèi)容。IRQ 相關(guān)內(nèi)容還需要顯式地設(shè)置(通過(guò)失衡的守護(hù)進(jìn)程),默認(rèn)來(lái)說(shuō),這不涉及內(nèi)核的 isolcpus 設(shè)置。但是,根據(jù)工作負(fù)載,可能需要調(diào)整,在任何情況下,如果有許多類似的主機(jī),安裝很容易被復(fù)制。有一個(gè)被叫做 partrt 的工具有助于建立隔離。
Libvirt 和 OpenStack
更高一層的 libvirt,不需要太多的規(guī)則,它僅僅會(huì)從高層上執(zhí)行命令。在 libvirt 1.2.13 上,所有必需的可調(diào)參數(shù)是可用的:設(shè)置可調(diào)參數(shù)(規(guī)則,優(yōu)先級(jí),阻塞物理 CPU),用 mlock()查詢 QEMU 所有的客戶機(jī)內(nèi)存(RAM),并啟動(dòng)虛擬機(jī)連接到 vhost-user 進(jìn)程。這些參數(shù)是由 OpenStack 計(jì)算節(jié)點(diǎn)的 Nova 組件處理的。
Nova 已經(jīng)可以被配置為虛擬 CPU(VCPU)阻塞并指定物理 CPU。其他的設(shè)置,在 OpenStack 中被錯(cuò)過(guò),這在一個(gè)藍(lán)圖(a blueprint)中已被討論。它還沒(méi)有被完成(舉例來(lái)說(shuō),它提供了聯(lián)合無(wú)實(shí)時(shí) CPU 到無(wú)實(shí)時(shí) QEMU 的線程),藍(lán)圖將會(huì)使得剩余的 libvirt 功能生效。補(bǔ)丁正在被討論,目標(biāo)是在 OpenStack 的“Mitaka”版本發(fā)布,大概是在 2016 年的上半年左右。 Kiszka 的團(tuán)隊(duì)會(huì)集成補(bǔ)丁部署;團(tuán)隊(duì)將會(huì)提出擴(kuò)展的補(bǔ)丁和藍(lán)圖。
OpenStack 是通過(guò) Neutron 組件控制網(wǎng)絡(luò)的。然而,實(shí)時(shí)網(wǎng)絡(luò)趨向于特殊:他們根本不使用TCP/IP,Neutron 想要使用自己的方式管理網(wǎng)絡(luò)。西門(mén)子(Siemens)說(shuō) Neutron 是“非托管型”網(wǎng)絡(luò)(沒(méi)有DHCP,甚至沒(méi)有IP)。
總而言之,工作在更高層上的棧主要是為有實(shí)時(shí)能力的計(jì)算節(jié)點(diǎn)的基本設(shè)置進(jìn)行標(biāo)準(zhǔn)化,許多工作是為了優(yōu)化參數(shù)處理,諸如 partrt。在問(wèn)答環(huán)節(jié),如前所述,也被擴(kuò)展以支持實(shí)時(shí)優(yōu)化參數(shù)文件。然而, Kiszka 還計(jì)劃著再看看更低的棧;最新的芯片有功能消除中斷延遲,當(dāng)直接分配設(shè)備給虛擬機(jī)的時(shí)候,不涉及到管理程序而直接路由中斷,另外,Kiszka 過(guò)去的工作[PDF]讓 QEMU 可以模擬實(shí)時(shí)設(shè)備并可以使其在未來(lái)恢復(fù)。