現代計算機具有足夠強大的能力來利用虛擬化技術支持多個虛擬機(VM: virtual machines),並且在每個虛擬機上各自運行單獨的操作系統實例。這直接導致了虛擬機技術發展的又一個春天。在本文中,我們提出了Xen,一個高性能的用於資源管理的虛擬機監視器(VMM: VM monitor)。Xen能夠支持的應用比如:server consolidation,co-located hosting facilities,distributed web services,secure computing platforms[12,16]和application mobility。
成功地對一台機器進行劃分,使它能夠支持多個操作系統的並發執行,這個過程具有很多的挑戰。首先,虛擬機必須是彼此相隔離的:如果一個虛擬機的執行會影響另一個的性能,這是不可以被接受的。這一點在操作各個虛擬機的用戶相互間並不信任的情況下顯得特別重要。其次,它必須支持多種多樣的不同操作系統以提供給各種異構(heterogeneity)的流行應用的支持(//這裡的異構指的是應用開發依托的操作系統不同,因此在實現上也就有很大差異,使得應用並不能夠跨平台移植,因為Xen不需要對應用程序進行修改,那麼它就必須支持各種常用的操作系統;所謂流行的應用,就是那些大家常用的、必需的應用)。第三,由虛擬化技術引入的性能開銷必須要小。
Xen操控(//host:操作和控制)的是常用的操作系統,但是需要對操作系統中的某些相關部分進行一些修改。在本文中描述和評估的Xen原型系統能夠支持多個我們研發的XenoLinux guest OS實例的並發執行;每個實例都給出了和非虛擬化情況下的Linux 2.4中相同的應用二進制接口。目前,我們對Windows XP到Xen的移植還沒有完全完成,但是已經能夠運行簡單的用戶空間進程。移植NetBSD的工作也在進行中。
Xen使得用戶能夠動態地實例化一個操作系統以執行他們需要的應用。在XenoServer項目[15,35]中,我們在ISP或者Internet exchange(//布置在這些場合中經濟劃算而且又具有戰略意義的地方)的標准服務器硬件上配置了Xen。我們在啟動一個新的虛擬機的時候需要執行許可控制(admission control),希望每個虛擬機能夠以某種方式為它需要的資源付出代價。我們在其它文章中討論過我們在這個方向上的思路和方法[21];現在這篇文章則將焦點關注於虛擬機。
現在有一些方法用於構建能夠在共享的機器上操控多個應用和服務器(//server:這裡提到的server應該是大規模應用的意思,比如數據庫服務器)的系統。也許最簡單的方法就是部署一個或多個運行著標准操作系統(如Linux或者Windows)的主機,然後允許用戶們安裝文件和啟動進程— 應用間的保護是由傳統的操作系統技術提供的(//這裡提到的做法,就是類似並行機性質的,各個節點都是獨立的主機,但是一個應用可以在多個節點上面並行執行)。實驗顯示:由於要針對各個脫節(//supposedly disjoint:邏輯上脫節,指的是應用不具有連貫性/兼容性,所以針對每個應用都要單獨配置一次,如果能想辦法將前後有關聯的應用放在一起執行,可以大大減少相關的開銷,如配置開銷,通信開銷等等)的應用進行復雜的配置,這些配置過程導致的交互行為會使系統管理任務迅速成為時間消耗巨大的任務。
更重要的是,這樣的系統不能夠充分地支持性能隔離;某個進程的調度優先級,存儲要求,網絡通信量和磁盤訪問等等特征都會影響到其它進程的性能。如果是在資源供應充足而且用戶群體是限定(比如計算網格或者PlanetLab平台實驗)的情況下,這個系統還是可以接受的。但是當資源是供不應求的時候,或者用戶間不相協作(//uncooperative:不相協作,比如用戶間的需求有沖突,那麼一定會互相影響的)的時候就不行了。一個解決這個問題的方法是改進對操作系統性能隔離的支持。這已經在resource containers,Linux/RK,QLinux和SILK中被或多或少地實現了。這些方法中存在著一個難點是難以確保所有的資源都能夠正確地分配給有相應資源需求的進程。例如,緩沖區cache或者存儲頁面的替換算法導致的在應用間的復雜的交互行為(//比如存儲頁面替換的時候,某個進程的頁面替換序列會干擾到其它進程的,要免除這個影響就需要有復雜的機制用於進程間的協調)。這就是存在於操作系統中的“QoS干擾問題(QoS crosstalk)”。在低層采用多路執行技術能夠緩解這個問題帶來的影響,這已經在Exokerne和Nemesis操作系統中得到證明。在這些操作系統中,任務間無意識的或者不受歡迎的交互行為被最小化了。
我們使用了同樣的基本方法來構建Xen。Xen就是以整個操作系統的粒度復用物理資源,它能夠提供在操作系統間的性能隔離。相對於進程級的資源復用,Xen要允許一定范圍內的guest OS“和平”共存,而並非去指定一個特殊的應用二進制接口(//如果限定了應用二進制接口,就意味著只能支持某個特定的操作系統)。為了獲得這種靈活性就必須付出一些代價 — 無論是在初始化過程(比如,boot和resume與fork和exec的比較)中,還是在資源消費上,運行一個完整的操作系統與運行一個進程相比分量都要重得多。
為了達到我們的能夠支持多至100個被操控的操作系統實例的目標,我們認為這些代價是值得付出的。付出這些代價後獲得的系統允許單個用戶在資源受控的形式下,直接運行那些不需要修改的二進制代碼或者二進制代碼集合(例如,後端為PostgreSQL的Apache服務器)。更進一步的,因為用戶能夠動態地精確創建他們的軟件所需要的執行環境,所以這個系統也就提供了在非常高的層次上的靈活性。另外,在各種服務和應用間的配置交互也是可以避免的(例如,每個Windows實例都有它們自己的寄存器文件)。
本文的余下部分是這樣組織的:第2部分解釋了我們的虛擬化方法和Xen的工作概況。第3部分描述了我們的設計和實現的關鍵特征。第4部分給出了使用業界標准的測試程序評估運行在Xen上的XenoLinux與單獨的Linux,VMware Workstation和用戶模式Linux(UML)的性能比較結果。最後的第5部分討論了未來的工作並作了總結。
2. XEN:方法和概述
在傳統的VMM中,虛擬硬件的功能是與底層機器上的真實硬件完全相同的。這種“完全虛擬化”(full virtualization)的方法最顯而易見的好處在於操作系統可以不經任何修改就直接在虛擬硬件上運行,但是它也有很多缺點。特別是針對那些當前被廣泛應用的IA32(或者稱作x86)架構,這種方法帶來的缺陷更是不容忽視。
x86架構的設計從來就不支持完全的虛擬化。如果要正確實現x86架構虛擬化,VMM就必須能夠對某幾條特定的“超級指令(supervisor instruction)”進行操作。但是,如果在沒有足夠特權的情況下執行這些超級指令會導致“沉默的失敗(//fail silently:如果特權級不夠,那麼會直接導致執行失敗,不會產生其它響應)”,而並非產生一個便於我們使用的陷阱(trap)。
另外,將x86架構中的MMU進行有效的虛擬化也是一件很困難的事情。這些問題是可以被解決的,但是在解決的同時必須要付出操作復雜度增加和系統性能降低的代價。VMware ESX Server[10]需要動態地重寫那些被VMM操控的機器碼部分,在其中有可能需要VMM干涉的地方插入陷阱操作(//在什麼地方插入陷阱操作,是在程序運行起來後才知道的,所以需要動態地重寫相關代碼)。因為務必要對所有那些不能夠引起陷阱的特權指令進行捕捉和操作,所以這種轉換(//動態重寫代碼)要被應用於整個guest OS的內核(導致了相關的轉換,執行和緩存等開銷)。ESX Server實現中采用的技術是建立系統結構(system structure)(比如頁表)的影子版本,通過為每一次“更新”操作設立陷阱來解決虛擬頁表和物理頁表的一致性問題(//具體細節還是要看ESX Server的說明)。但是在處理“更新密集”型的操作(如創建新的應用進程)的時候,該方法會帶來高昂的開銷。
除了x86架構非常復雜的原因,還有一些其它方面的爭論反對“完全虛擬化”。其中值得一提的是,被操控的操作系統在一些情況下需要接觸到真實的資源。例如,提供真實時間和虛擬時間以允許guest OS能夠更好地支持“時間敏感”型的任務,還可以正確地操作TCP超時和RTT估算;給出真實的機器地址以允許guest OS能夠利用超級頁(superpage)或者頁染色(page coloring)等方法改進性能。
我們提出的虛擬機抽象能夠避免完全虛擬化帶來的種種缺陷。這種虛擬機抽象和底層硬件相似卻並不完全相同,因此被稱之為“准虛擬化”(//paravirtualization:或者翻譯為半虛擬化?後面譯文沿用准虛擬化)方法。這種方法雖然需要對guest OS進行一些改動,但是它能夠改善性能。還有特別重要的一點需要說明:准虛擬化方法不會對應用二進制接口(ABI)進行修改,因此用戶也就不用修改那些在guest OS上執行的應用程序。
我們進行的關於准虛擬化方法的討論要遵循以下一些規則:
1.最基本的是要支持那些不經改動的應用二進制文件的執行,即用戶不用對應用程序做針對Xen的轉換。因此我們必須虛擬化現有的標准ABI所需的全部體系結構特征。
2.很重要的一點是要支持完整的多應用操作系統。這就需要將在單個guest OS實例中的復雜的服務器配置虛擬化(//例如,如果guest OS上配置了ftp服務,那麼虛擬硬件就要打開相應端口)。
3.准虛擬化務必要有很高的性能。另外針對那些不協作(//uncooperative:這裡的不協作是指硬件架構不支持共享,所以才需要資源隔離)的機器架構,如x86架構,准虛擬化還需要能夠提供很強的資源隔離能力。
4.在協作(cooperative)的機器架構上,准虛擬化方法要能夠完全地隱藏資源虛擬化帶來的影響,減少guest OS在正確性和性能上面臨的風險。
請注意,我們在這裡提出的准虛擬化的x86抽象的方法是與最近在Denali項目中提出的方法有很大差異的。Denali是為了支持數以千計的運行著網絡服務的虛擬機而設計的。這些網絡服務中絕大部分是小規模的,不流行(//應用的不流行也就說明了運行該應用的環境比較少,所以只要針對這些相應的特定環境作專門的虛擬化即可)的應用。與之相反的是,Xen的設計最終要支持近100個運行著業界標准應用和服務的虛擬機。由於設計目標的極大差異,我們不妨將Denali的設計選擇和我們自己的設計規則做一個有益的討論。
首先,Denali不需要關注現有的ABI,因此他們的VM接口忽略掉了相關的架構特征。例如,Denali並不完全支持x86的分段機制,但是這一點卻是在NetBSD,Linux和Windows XP等操作系統的ABI中都有提出並且被廣泛使用。例如,線程庫中經常會使用分段機制來尋址線程局部數據。
其次,Denali的實現沒有解決在單個guest OS中支持多個應用(application multiplexing)的問題,也沒有解決多地址空間的問題。應用被顯式地鏈接到Ilwaco guest OS實例上,這麼做在某種意義上類似於之前在Exokernel中的libOS[23]。因此每個虛擬機只能操控一個單用戶單應用的沒有保護措施的所謂的“操作系統”。在Xen中,與之相反,每個虛擬機上能夠操控一個真正的操作系統。這個操作系統上能夠安全地執行數以千計個不經改動的用戶級進程。雖然Denali號稱開發了一個虛擬MMU原型能夠對其在該領域有所幫助,但是我們沒有看到公開的技術細節和評估報告。
再次,在Denali體系結構中,是由VMM執行全部的內存與磁盤間的頁面調度的。這可能是與虛擬層缺乏存儲管理支持有關。由VMM完成頁面調度是與我們的性能隔離目標相違背的:那些“有惡意”的虛擬機可能會故意產生抖動行為,導致其它虛擬機的CPU時間和磁盤帶寬被不公平地剝奪(//VMM監控很多VM,各個VM上再跑操作系統,所以如果很多事情都放在VMM中做必然會影響到各個VM;所以要把一些事情放在上面的操作系統做來達到隔離性)。在Xen中,我們希望每個guest OS在其自己分配到的內存空間和磁盤區域內執行它自己的頁面調度(此前已經有self-paging的方法被提出)。
最後,Denali為機器的全部資源虛擬了“名字空間”。這樣的話,如果一個VM不能夠“叫出”另一個VM下轄的資源的名字,那麼該VM就不能夠訪問這些資源(例如,Denali中的VM並不知道硬件地址,它們只看得到Denali創建的虛擬地址)。與此相對,我們認為hypervisor中的安全訪問控制已經足以確保安全性;此外,就像之前討論過的,當前在guest OS是否應該能夠直接看到物理資源這一點上存在著很熱烈的關於正確性和性能的爭論。
在後續的章節裡,我們將描述Xen提出的虛擬機抽象,然後將討論如何將一個guest OS作必要的改動以適應Xen。在這篇文章裡我們定義了一些術語要提醒大家注意。例如,術語guest OS是指Xen能夠操控的操作系統之一;術語domain是指一個運行中的虛擬機,在其上有一個guest OS在執行。program和process之間的區別和傳統系統中的區別類似。我們稱Xen本身為hypervisor,因為它運行的特權級要比它所操控的guest OS中的supervisor code運行的特權級更高。
2.1 虛擬機接口
一個准虛擬化的x86接口主要包括了系統中的三個大的方面:存儲管理,CPU和設備I/O。在下面,我們將依次介紹各個機器子系統的情況,並討論在我們的准虛擬化架構中是如何體現的。雖然在我們的實現中,有相當一部分,如存儲管理,是專門針對x86的,但是實際上還有很多方面(比如我們虛擬的CPU和I/O設備)都是可以很容易地應用於其它機器架構上的。更進一步地說,在與RISC架構在實現上有差異的很多地方,x86往往表現出的是該方面最壞情況時的情形。例如,對硬件頁表進行有效的虛擬化就比虛擬化一個軟件管理的TLB困難很多。
存儲
管理分段不能夠使用具有完全特權級的段描述符,不能夠與線性地址空間的最頂部交迭(//因為最頂部是Xen)。
分頁guest
OS直接對硬件頁表做讀訪問,但是更新(//就是寫)是分批進行的而且要經過hypervisor確認。一個domain可以被分配在不連續的頁面上。
CPU保護guest OS必須運行在低於Xen的特權級上。
異常guest OS必須將異常句柄的描述符表在Xen中記錄。除了頁面錯誤外,其它句柄和真實的x86架構相同。
系統調用guest OS為系統調用提供一個“快速”的句柄。允許應用直接調用它所在的guest OS,而不必間接地通過Xen完成每次調用。
中斷硬件中斷被一個輕量級的事件系統替換。
時間每個guest OS具有一個定時器接口,可以得到“真實的”和“虛擬的”時間。
設備I/O網絡,磁盤,……虛擬設備訪問起來很簡單。數據傳遞使用的是異步I/O環。由一個事件機制替換硬件中斷來發布通告。
2.1.1存儲管理
虛擬化存儲毫無疑問是准虛擬化一個體系結構中最困難的部分,它包括hypervisor所需的機制和移植各個guest
OS所需的改動。如果在架構中提供了由軟件管理的TLB的話,那麼這個任務會變得輕松些,它們可以以比較簡單的方式被有效地虛擬化[13]。帶標記的TLB是另外一個在大部分RISC架構(這些RISC架構主要用於構建服務器,比如Alpha,MIPS和SPARC)中支持的有用特征。其中,每個TLB項都有和地址空間標識符相關的標記,這使得hypervisor和各個guest OS能夠有效地在被隔離開的地址空間內共存。這時在執行轉移(//transferring execution:在進程執行間切換的時候,執行的指令序列從一個進程轉移到另一個進程,稱為執行轉移)的時候,是不需要刷新(flush)整個TLB(//只對具有和自己的地址空間標識符相吻合的TLB項進行操作)。
不幸的是,x86架構並沒有由軟件管理的TLB;取而代之的是在發生TLB失效的時候,處理器會自動通過遍歷硬件頁表結構來處理。因此為了獲得最好的可能達到的性能,當前地址空間內所有的有效頁傳輸)都要在硬件可訪問的頁表中給出(//最好情況理應如此,但實際如何做得到呢?)。此外,因為TLB是沒有標記的,所以地址空間的切換需要整個TLB的刷新。在這些限制下,我們作出了兩個決定:(i)由guest OS負責分配和管理硬件頁表,這麼做最小化了Xen對頁表操作的影響,確保了安全性和隔離性;(ii)Xen處於每個地址空間的最頂部的64MB空間內,因此避免了在進入和離開hypervisor時進行TLB刷新操作(//這個要看源代碼才能最後搞清楚)。
每當guest OS需要一個新的頁表,例如創建了一個新進程,它就在自己保留的內存空間內分配和初始化一個頁面,並且將其在Xen中記錄。此時操作系統必須放棄對頁表存儲空間直接寫的權限:所有後續的更新操作都必須由Xen進行確認。這就在很多方面限制了更新操作,包括只允許操作系統它自己所屬的頁進行映射操作,不允許對頁表進行可寫的映射操作。guest OS可以成批地進行更新操作以減少每次更新都要進入hypervisor帶來的代價(//因為每次更新都要hypervisor確認)。每個地址空間頂部的64MB區域是保留給Xen的,是不能夠被guest OS訪問或者重新進行映射的。因為任何通常的x86架構中的ABI都不會使用到這個區域中的地址,所以這個約束不會破壞到應用程序的兼容性。
分段機制也是以類似的方式,通過對硬件段描述符表的更新確認來進行虛擬化(//這樣做就達到虛擬化的目的了麼?哦,應該是Xen在確認後接著由Xen執行,嗯)。對於x86架構上段描述符的限制只有:(i)它們的特權級別必須比Xen要低;(ii)它們不能夠對地址空間中Xen的保留部分進行訪問。
2.1.2CPU
虛擬化CPU對guest OS提出了幾個要求。因為hypervisor插在操作系統的下層違背了慣常的關於操作系統在整個系統中特權最高的假設。為了保護hypervisor不會受到操作系統不正確行為的影響(即domain不受另一個domain的影響),guest OS就必須被改造為能夠運行在較低的特權級上。
很多處理器體系結構只是提供了兩個特權級。在這些情況下,guest OS和應用程序共享較低的特權級。同時,guest OS運行在單獨的地址空間中以保護自己不會受到應用程序執行的影響。guest OS通過hypervisor設定虛擬的特權級和改變當前的地址空間來間接地和應用之間進行控制傳遞。另外,如果處理器的TLB支持地址空間標記,那麼也就可以避免TLB刷新帶來的高昂代價。
在x86架構上有效地實現特權級的虛擬化是可能的,因為x86架構在硬件上支持四個不同的特權級。x86架構的特權級往往用圈(ring)來表示,從ring 0(最高特權)到ring 3(最低特權)。操作系統的代碼運行在ring 0這個特權級上,因為再沒有其它的ring能夠執行那些特權指令。ring 3通常用於執行應用代碼。就我們所知,自OS/2起到現在的各個知名的x86 架構上的操作系統都還沒有利用ring 1和ring 2這兩個特權級的。那麼,任何遵循這個通常的安排的操作系統(//沒有利用ring 1和ring 2)就都可以移植到Xen上來。
這個移植過程只需要做一些改動使操作系統改為運行在ring 1特權級上。這就防止了guest OS會直接執行特權指令,也保證了操作系統與運行在ring 3上的應用程序之間相隔離的安全性。
特權指令需要被Xen確認和執行以達到准虛擬化的目的,這主要應用於諸如安置新的頁表,或者在處理器idle時放棄之(而不是去hlt它)等操作。因為只有Xen有足夠高的特權級來執行這些指令,所以任何guest OS試圖直接運行特權指令都會失敗,後果要麼是“沉默”要麼是產生錯誤。
異常,包括內存錯誤和軟件陷阱,都可以在x86架構的基礎上直接進行虛擬化。有一個表,內容為對每類異常進行描述的句柄。表中所列的異常都是在Xen中有記錄的,以用作確認。表中給出的句柄都是與真正的x86硬件中相同的;之所以這一點是可能做到的,主要是因為在我們的准虛擬化架構中,異常堆棧框架是沒有被修改的。唯一的一個改動是在頁面錯誤句柄上。因為該句柄的操作需要從特權處理器寄存器(CR2)中讀出出錯的地址;但是這是不可能的(//因為特權級別不夠了),我們就將它(//頁面錯誤句柄?CR2的值?)寫入擴展的堆棧框架中(後來發現,在移植XP的時候,將這個值寫入一個預先商定的共享存儲位置上要比修改堆棧框架簡單一些)。當系統在ring 0以外執行時有異常發生,Xen的句柄就會在guest OS堆棧中創建一個異常堆棧框架的拷貝,並且會將控制交給相應的已經記錄過的異常句柄。
典型的,只有兩類異常會經常發生而影響到系統的性能:系統調用(一般都是通過軟件異常實現)和頁面錯誤。我們讓每個guest OS都記錄一個“快速的”異常操作句柄來改進系統調用的性能。這個異常操作句柄可以直接由處理器使用,而不必非要間接地經過ring 0;這個句柄在放置進硬件異常列表中之前就是經過確認的(//所以不必經過Xen)。不幸的是,我們不可能使用同樣的技術來處理頁面錯誤句柄,因為只有那些運行在ring 0的代碼才能夠從寄存器CR2中讀出錯誤的地址;因此,頁面錯誤必須要經過Xen才能提交,Xen保存該寄存器的值供來自ring 1的訪問使用。
當Xen發現異常產生時,它會對異常句柄進行確認以確保安全性。這只需要檢查句柄的代碼段中是否含有指明要在ring 0中執行的操作。既然沒有guest OS能夠創建這樣一個段,那麼只需要將專門的段選擇符和少量的保留在Xen中的靜態值作比較即可。除了這點以外,任何其它的句柄問題都會在異常傳播(exception propagation)(//一個異常導致了另一個異常的產生)的過程中被修正。例如,如果句柄缺少相應代碼段或者句柄沒有分配到內存頁,那麼在Xen為將控制返回給句柄而執行iret指令的時候就會有一個相應的錯誤產生。Xen通過檢查出錯的程序計數器值來檢測這些“雙錯誤(//double faults:之前已經出錯了,現在到了iret已經是第二個錯誤了;第二個錯誤是由第一個錯誤傳播而來)”:如果地址是處於異常虛擬化的代碼中(//說明異常處理沒有完成,iret沒成功),那麼guest OS就要被終止。
對於直接的系統調用句柄來說,這種“懶惰(//第一個錯誤發生的時候,沒有被檢查到;直到Xen執行了iret之後才報錯)”的檢查也是安全的:當CPU試圖直接跳至guest OS句柄的時候,會發生訪問錯誤(//之前的過程都一樣,只是直接的系統調用是不經過Xen的)。在這種情況下,產生錯誤的地址將處於Xen之外(因為Xen不會去執行guest OS系統調用),因此錯誤就以上文講過的一般方式進行虛擬化即可。如果由於錯誤的傳播導致了進一步的“雙錯誤”,那麼guest OS會像上文談及的一樣被終止。
2.1.3設備I/O
在完全虛擬化環境下需要仿真現有的硬件設備,而Xen不同於此。Xen給出了一套清楚、簡單的設備抽象。這就使得我們能夠設計一個接口以有效地滿足我們對保護性和隔離性的需求。為了做到這一點,I/O和各個domain之間的數據傳遞都是要經過Xen的,可以使用的方法有共享內存,異步緩沖區描述符環等。這些方法能夠在Xen有效地執行確認檢查(例如,檢查緩沖區是否包括在了domain的存儲空間內)的同時,為在系統中的豎直方向上傳遞緩沖區信息提供了一個高性能的通信機制。和硬件中斷類似,Xen支持一個輕量級的事件遞交機制用於為一個domain傳送異步通告(notification)。這些通告是在對未決事件類型的位圖進行更新的時候產生的,也可以通過調用一個guest OS專有的事件句柄產生。這些調用的返回可以由guest OS來決定是否進行“拖延”處理。例如,這麼做(//拖延處理)可以避免在頻繁喚醒通告時帶來的額外開銷。
2.2移植OS到Xen的代價
當前我們的NetBSD移植還處於非常初級的階段,因此我們就沒有將其結果在這裡報告。雖然XP的移植要更進一步,但也還處於移植過程中;當前移植的XP能夠執行RAM上的用戶空間的應用,但是缺乏虛擬的I/O驅動。基於這個原因,表中就沒有給出和XP的虛擬設備驅動相關的數據。無論怎樣,和Linux一樣,我們可以想見這些驅動應該是小的和簡單的,因為這要得益於Xen提供的理想的硬件抽象。
衡量代價的標准是與原先的x86代碼相比修改或增加的那些必要的注釋以及遵從一定格式的代碼的行數(不包括設備驅動)。對Windows XP中體系結構無關(architecture independent)的代碼所作的改動達到了一個驚人的數字,這是因為Windows XP使用了多種多樣的結構和聯合來訪問頁表項(PTE)。每次對頁表的訪問都不得不被單獨地進行修改(//因為每次訪問都可能用到不同的結構),當然這個過程是可以采用一些腳本來自動完成的。與此相反的,Linux需要的改動就少了很多,這是因為Linux的存儲系統是使用預處理程序中的宏來訪問PTE的— 這些宏定義為增加准虛擬化所需的轉換和hypervisor調用提供了便利的位置(//就在這些位置上加即可)。
在這兩個操作系統中,體系結構特有(architecture specific)的部分用於將x86代碼向我們的准虛擬架構的移植。這包括重寫那些使用了特權指令的程序,刪除大量的低層的系統初始化代碼。另外,Window XP需要有更多的改變,這主要是因為之前遺留下來的16位仿真代碼的存在以及需要一個略有不同引導加載(boot-loading)機制。注意,XP中的x86特有的代碼要比Linux多很多,因此可以預見到在做移植的時候也就需要做更多的工作。
2.3控制和管理
貫穿於整個Xen的設計與實現過程中,有一個目標就是盡可能地將策略從機制當中剝離出來。雖然hypervisor必須要被包含在數據通路(data-path aspects)上。例如,在domain之間調度CPU,在發送之前過濾網絡數據包,或者在讀數據塊的時候進行執行訪問控制(//必然的,因為Xen位於guest OS和底層硬件之間,guest OS又是彼此隔離的,所以數據傳遞是一定都要經由Xen的)。但是在更高層次的問題上,例如CPU如何被共享或者各個domain能夠發送哪種數據包,這時就不需要將Xen包括在內了,甚至都不用考慮它(//hypervisor是實現機制,而如何共享CPU和如何進行任務分工都是策略問題)。
最終得到的架構是hypervisor只是提供那些最基本的控制操作。這些操作經由一個可訪問的接口從經過授權的domain傳來;而那些復雜的策略決策,比如許可控制(//不知道這個許可控制是否和第1部分裡提到的是一回事兒),都最好由運行在guest OS上的管理軟件執行,而並非在有特權的hypervisor代碼中(//Xen只是提供機制,不負責策略)。
整個系統架構中有一個domain是在引導(boot)時創建的。這個domain被允許使用控制接口。這個初始的domain,術語稱為Domain 0,它負責操控應用級的管理軟件。控制接口具有創建和終止其它domain的能力,還能控制它們相關的調度參數、物理存儲分配以及它們對給定的物理磁盤和網絡設備的訪問。
除了處理器和存儲資源,控制接口還支持虛擬網絡接口(VIF)和塊設備(VBD:虛擬塊設備)的創建和刪除。這些虛擬I/O設備具有一些和訪問控制相關的信息。這些信息決定了哪個domain能夠訪問它們,以及訪問時有哪些約束(例如,一個只讀的VBD可以被創建,一個VIF可以過濾IP包以防止源地址欺騙)。
這個控制接口,結合對系統當前狀態進行的剖析統計,其結果能夠被輸出到一套運行在Domain 0上的應用級管理軟件上。該管理軟件作為管理工具的補充,能夠對整個服務器進行方便地管理:例如,能夠創建和破壞domain,設定網絡過濾器和路由規則,在數據包和數據流兩個粒度上監視每個domain的網絡活動,創建和刪除虛擬網絡接口和虛擬塊設備。我們期待開發出高級的工具來進一步將管理策略的應用程序自動化(//這裡的管理策略和前面講的“機制與策略分開”中的策略不是一回事兒吧?)。
ccid_page/>
3. DETAILED DESIGN — 細節設計
在這一部分,我們介紹構成基於Xen的服務器的各個主要子部分的設計細節。在各個設計中,我們對Xen和guest OS的功能作了清楚的說明。當前的關於guest OS的討論主要集中於XenoLinux,這主要是因為這個guest OS是目前發展最成熟的;但是我們對於當前正在進行中的對Windows XP和NetBSD的移植工作也是很有信心的。我們相信Xen可以支持多種多樣的guest OS。
3.1 控制傳遞:hypercalls和事件
有兩種機制用於Xen和其上的domain之間進行控制的交互:使用hypercall產生從domain到Xen的同步調用;使用異步事件機制完成從Xen到domain的通告遞交。
hypercall接口允許domain通過執行一個同步軟陷阱陷入到hypervisor執行一個特權操作,這類似於在傳統的操作系統中對系統調用的使用。舉一個使用hypercall的例子:一組頁表更新的請求,要經過Xen確認並且完成相應的更新操作(//更新是要由Xen確認並完成的,需要特權操作,所以這時要利用hypercall陷入到hypervisor中),在更新完成後再由Xen將控制返回給產生本次調用的domain。
從Xen到domain的通信是由一個異步事件機制提供的。這個機制取代了常用的利用設備中斷的遞交機制,它允許那些重要事件(如domain-termination request)采用輕量級的通告形式。和傳統的Unix信號類似,這些重要事件的個數比較少,但每一個都用作針對某一特定類型事件的標記。例如,用於在網絡上指出新的數據已經被接收到的事件,或者表示一個虛擬磁盤請求已經完成的事件。
那些未決的事件存放在每個domain的bitmask(//一個專門的數據結構)中。bitmask的更新要由Xen在調用一個和guest OS相應的事件調用返回句柄之前完成(//Xen針對某類事件要向上發通告,如果Xen調用了guest OS相應的事件調用返回句柄,就說明該事件完成了,下面要把控制交回給domain,所以必然要在調用事件調用返回句柄之前由Xen將bitmask更新)。調用返回句柄負責重新設置未決事件集合(//調用返回句柄仍舊是由Xen操作,更新bitmask),同時以相應的行為和通告相呼應。一個domain可以通過設置一個Xen可讀的軟件標記來顯式地推遲對事件操作:這一點是與在真實的處理器中禁止中斷的過程類似的。
3.2 數據傳遞:I/O環
hypervisor的存在意味著在guest OS和I/O設備之間有一個額外的保護域,所以數據的傳遞機制就變得至關重要。數據傳遞機制使得數據能夠在系統中沿著豎直方向移動,同時具有盡量小的開銷。
有兩個主要方面構成了我們對I/O傳遞機制的設計:資源管理和事件通告。為了做到resource accountability,我們在接收到一個來自設備的中斷後,要盡量減少在將多路數據分解(//demultiplex data:分解多路數據,數據自硬件設備傳來,需要傳遞給各個指定的domain中的guest OS中執行,這裡就存在一個多路選擇的問題來確定究竟把數據傳給哪個domain;一旦確定了數據是傳給哪個domain的,也就說明了此時是哪個domain在使用相關設備,做到了resource accountability)到一個特定的domain中所做的工作 —
管理緩沖區帶來的開銷是在計算任務分配給相應的domain後產生的(//任務分給domain後,domain才開始對任務數據所處的那部分緩沖區進行管理,而並非用其它的機制對整個緩沖區統一管理,那樣會增加復雜性,而且缺乏保障)。類似的,設備I/O的訪存操作也是由相應的domain提供的,這麼做可以防止由於共享緩沖池導致的相互間的干擾(//如果I/O能夠直接訪存而不經過domain管理的話,就會產生混亂,比如不清楚I/O操作存取到的數據是屬於哪個domain的);I/O緩沖在數據傳遞過程中通過Xen內部綁定(pin)到底層頁框上面的方法來獲得保護。
I/O描述符環是一個循環隊列,它由domain分派的描述符組成,可以從Xen內部訪問到。描述符中並不直接包含有I/O數據;取而代之的是,I/O數據緩沖被guest OS在帶寬外分配再間接地由I/O描述符引用(//I/O描述符環的容量是有限的,所以I/O數據要先進行分配,再做向I/O描述符環上的映射;所謂out-of-band:帶寬外,就是在分配數據時可以超出I/O描述符環的限制)。每次環訪問都要基於兩對生產者-消費者指針:domain通過推進請求生產者指針將一個請求放置在環上;Xen處理這些請求,推進一個相關的請求消費者指針。響應被放回在環上也是類似的,只是由Xen作為生產者,guest OS作為消費者。這裡是不要求請求是被按順序被處理的:guest OS給每個請求都建立了一個唯一的相關標識符,這個標識符會在相關的響應上被復制(//描述符環只是限定了能夠處理請求的規模,並不規定處理順序,誰先被處理誰後被處理是在將數據映射到描述符環上的時候決定的)。這就允許Xen出於調度和優先級的考慮,重新排定I/O操作的順序。
這個結構是通用的,足以支持很多不同的設備范例。例如,如果一組“請求”要為網絡數據包的接收提供緩沖,那麼相應的後續“響應”就是數據包已經到達緩沖區的信號。重新排序在處理磁盤請求時是很有用的(//比如兩個domain請求都要讀同一塊數據,那麼就可以把這兩個請求的處理放到一起完成,提高效率),它允許它們在Xen內部被調度以提高效率;使用帶寬外緩沖的描述符使得能夠容易地實現零復制傳輸(//減少了數據拷貝,如果不用描述符的話,那麼就務必要將緩沖區的數據內容在I/O環中進行復制,而現在做的只是映射操作,即零復制)。
我們將請求和響應的產生和其它的通告分開:在請求的情況下,一個domain可以在調用一個hypercall陷入Xen之前將多個項排入隊列;在響應的情況下,一個domain能夠通過劃定一個相應的閥值來推遲通告事件的遞交。這使得每個domain能夠權衡延遲和吞吐量的需求,類似在ArseNIC吉比特以太網接口的flow-aware(//流優化?)的中斷分派[34]。
3.3 子系統虛擬化
前文描述的控制和數據傳遞機制被使用在我們對各個子系統的虛擬化實現中。在下面,我們討論如何獲得對CPU,定時器,內存,網絡和磁盤的虛擬化。
3.3.1CPU調度
Xen當前對domain的調度采用的是Borrowed Virtual Time(BVT)調度算法[11]。我們之所以選擇這個特別的算法是因為它是工作保養型的,同時還具有特殊的機制使得它能夠在接收到一個事件時可以低延遲地喚醒(或者說分派)一個domain。快速的分派(//dispatch,就是類似前面說的demultiplex data)對於減少虛擬化對那些對時間敏感的操作系統子系統造成的影響是尤其重要的(//分派越快速,事件就越能及時到達操作系統);例如,TCP要依賴於確認信息的及時遞交以正確地估測在網絡上往返所用的時間(//如果確認信息沒有及時到達,那麼時間估測就有問題了)。BVT provides low-latency dispatch by using virtual-time warping, a mechanism which temporarily violates `ideal' fair sharing to favor recently-woken domains(//不很明白BVT算法的實現)。當然,其它調度算法也能夠在我們的通用調度器抽象上實現。每個domain的調度參數可以由運行在Domain 0的管理軟件進行調整。
3.3.2 時間和定時器
Xen為每個guest OS提供了真實時間,虛擬時間和掛鐘時間(wall-clock time)等三個概念。真實時間是以納秒為單位給出的,是從機器引導起來開始計算的時間,它記錄的是精確的處理器執行的時鐘周期數,時鐘周期能夠被外部時鐘源鎖頻(例如,通過NTP時間服務)。domain的虛擬時間只是在它運行的時候才會被記入:這主要供guest OS的調度器使用來確保guest OS上的應用進程能夠正確地共享時間片。最後,掛鐘時間是一個偏移,用於加到當前的真實時間上。掛鐘時間能夠被調整(//比如在各個guest OS中的時間可以不同,有的是上午九點,有的是下午三點,改的就是這個值),同時不會影響真實時間的流逝。
每一個guest OS能夠對一對警鐘定時器進行編程,一個用於真實時間,另一個用於虛擬時間。guest OS能夠維護內部的定時器隊列(//很多應用程序都有定時需求,真實的或者虛擬的,特別是網絡應用;guest OS要對這些定時需求排隊以確定誰的時間要求最緊迫,然後就盡量依次滿足它們;只要有一個定時需求沒被滿足,即超時了,那麼系統就產生異常)並使用Xen提供的警鐘定時器來觸發最早的超時。超時事件將會使用Xen事件機制來遞交。
3.3.3虛擬地址轉換
和其它子系統一樣,Xen也努力以盡可能小的開銷實現存儲訪問的虛擬化。正如2.1.1中討論的,由於x86架構使用的是硬件頁表,因此達到這個目標有些難度。VMware中使用的方法是為每個guest OS提供虛擬的頁表,這個頁表對於存儲管理單元(MMU)是不可見的[10]。然後由hypervisor負責陷入對虛擬頁表的訪問,確認更新,再將這些改變傳播到虛擬頁表和MMU可見的“影子”頁表(//“影子”頁表在第2部分提到過)。這大大增加了這個guest
OS操作的代價,比如創建一個新的虛擬地址空間,需要對“訪問過的”和“髒的”比特位上的硬件更新進行顯式地傳播。
之所以完全虛擬化要強迫使用影子頁表,是因為它要給出連續的物理內存的假象,而Xen就不拘泥於此。實際上,Xen只需要考慮對頁表的更新,來防止guest OS導致不可接受的改變。因此我們避免了和使用影子頁表相關的開銷和額外的復雜度 — Xen中的方法是直接地由MMU記錄guest OS的頁表,並且限制住guest OS只能做讀訪問。頁表更新通過hypercall傳遞給Xen;更新請求在被采納以前經過確認,這麼做就確保了安全性。
為了有助於確認,我們給機器的每個頁框都建立了一個相關的類型和引用數。一個頁框在任何時候都會排它地具有下述的某一個類型:頁目錄(PD),頁表(PT),局部描述符表(LDT),全局描述符表(GDT)。同時,這個頁框還可能是可寫(RW)的類型。一個guest OS可以為它自己所屬的頁框創建可讀的映射,而不必理會頁框的當前類型。一個頁框只有在它的引用數為0的時候,才能被安全地重新分配給其它任務使用。這個機制被用於滿足系統對安全性一貫的需求;例如,一個domain不能夠任意地對頁表的某個部分建立可寫的映射,如果要這麼做的話就必須要求頁框同時具有PT和RW類型(//什麼情況下是可讀的映射?什麼情況下又是可寫的映射呢?)。
類型系統還要被用於跟蹤那些用於頁表的頁框中哪些是已經被確認過的(//頁框用於頁表,即頁內容填入頁框)。這時,guest OS要指出頁框是否被分配用作頁表 — 這就需要在頁框的類型被定為PD或者PT後(//說明頁框是用於頁表的),由Xen對頁框中的每一項做一次性地確認,直至後來由guest OS發出釋放(unpin)的請求(//由guest OS釋放頁框)。這在改變頁表基指針的時候是很有用的,因為它不需要在每一次上下文切換時都對新頁表進行確認(//因為現在只確認頁框了)。注意,一個頁框在被釋放並且引用數為0之前是不能夠被重新分配給其它任務的,這樣就避免了guest OS可能會繞開引用數機制而直接利用釋放請求導致的危險。
為了減少所需的hypercall調用的次數,guest OS能夠在利用一個hypercall進行整批處理之前在局部將更新排入一個隊列。特別是在創建新的地址空間的時候,這一點是尤其有好處的。但是無論怎樣,我們必須確保更新被提交得足夠早以保證准確性。幸運的是,一個guest OS在第一次使用一個新的映射前要執行一次TLB刷新:這確保了任何被緩存的改變(//這些改變目前僅存於TLB中,還沒有被寫入內存頁表項)都是沒有經過確認的。因此,在TLB刷新之前立即提交那些待處理的更新就可以滿足正確性(//更新的時間,解決了什麼時候進行成批更新操作以保證正確性的問題)。可是,有一些guest OS會在TLB中沒有陳舊表項存在(//沒有陳舊表項意味著更新都已經送達內存中?)的時候省略掉這個刷新的步驟。在這種情況下,就有可能發生第一次試圖使用新的映射時會發生缺頁錯誤(//因為沒有刷新TLB)。 這時,guest OS錯誤句柄就必須要核查是否需要更新;如果需要的話,TLB就要被刷新(//加入所缺的內容),並且將導致剛才缺頁錯誤的指令重新執行。
3.3.4物理內存
為各個domain進行的初始的內存分配,或者說內存保留,都是在domain被創建的時候進行的;因此,內存在domain之間是靜態劃分的,這就提供了強大的隔離性。最大允許的內存保留量是被規定了的:如果某個domain中的內存壓力增加了,那麼它就可以從Xen爭取額外的內存頁,直到達到規定保留量的上限。反過來,如果一個domain希望節省些資源,避免不必要的開銷,它也能夠通過釋放內存頁給Xen來減少它的內存保留量。
XenoLinux實現了一個氣球驅動 [42](//沒看相關文獻),它能夠通過在Xen和XenoLinux的頁面分配器之間傳遞內存頁來調整domain的內存使用。雖然我們能夠直接修改Linux的內存管理例程,但是氣球驅動能夠利用現有的操作系統功能來進行調整,因此簡化了Linux的移植工作。無論怎樣,准虛擬化能夠被用於擴展氣球驅動的能力。例如,guest OS中的內存越界處理機制能夠被修改為通過向Xen請求更多的內存頁來自動地減輕內存壓力。
大部分操作系統都假定內存空間是由大量的較大規模的連續區域組成的。由於Xen並不保證它為guest OS分配的內存區域是連續的,所以guest OS需要為它們自己創建連續的物理內存的假象,即使它們實際在底層分配到的硬件內存是稀疏的。guest OS通過簡單地維護一個以實際分得的頁框號為索引的數組,來完全負責從實際分得的地址(physical)到硬件地址的映射。Xen提供了一個共享的地址轉換數組,這個數組用於支持從硬件地址到各個domain實際分得地址的映射,它是所有的domain都可讀的 — 更新這個數組是經過Xen確認的,以確保guest OS能夠擁有相應的硬件頁框。
即使一個guest OS在大多數情況下選擇了忽略硬件地址(//因為guest OS喜歡在連續的地址空間上運行),但是在它訪問它所擁有的頁表的時候(這時必須使用硬件地址)必須使用轉換表。硬件地址也可以暴露給操作系統存儲管理系統中的有限的某些部分以優化存儲訪問(//具體是哪些部分可以直接“看到”硬件地址呢?)。例如,一個guest OS可以分配特定的硬件頁用於優化以實際分得地址為索引的緩存中的布局,或者使用超級頁將硬件內存中的連續部分作自然對齊的映射。
3.3.5網絡
Xen提供了虛擬防火牆—路由器(VFR)的抽象,每個domain都有一個或多個在邏輯上附屬於VFR的網絡接口(VIF)。VIF看上去有些現代的網卡:具有兩個I/O緩沖區描述符環,一個用於發送一個用於接收。在每個方向(//發送或者接收)上都有一些相關的規則形式(,)— 如果模式(pattern)匹配上的話,那麼相關的動作(action)就會被起用。
Domain 0負責插入和刪除規則。例如在典型的情況下,可以增加規則防止源IP地址欺騙,或者增加規則確保基於目的IP地址和端口的正確的數據分派(demultiplexing)。規則也可以是和VFR上的硬件接口相關的。特別是我們增加的那些用於執行傳統的防火牆功能的規則,比如防止在不安全的端口上建立連接的企圖。
為了發送一個數據包,guest OS簡單地將緩沖區描述符排隊進發送環中。Xen復制描述符,同時為了確保安全性,還要復制數據包頭並執行匹配過濾規則。數據包的有效載荷不會被復制,因為我們使用的是分散—集中式(scatter-gather)的DMA;這裡要注意的是,相應的頁框必須被綁定,直到數據包傳送完成。為了保證公平性,Xen在數據包調度器上實現了簡單的循環輪轉(round-robin)算法。
為了有效地實現數據包的接收,我們需要guest OS為每一個它接收到的數據包交換一個沒有使用的頁框(//這個招兒挺絕的,我就不將頁內容復制到我自己的頁框裡了,直接把這個頁框納入自己的旗下,然後再換個我沒用的空頁框給你,反正只要修改地址轉換數組就可以了);這就避免了需要在Xen和guest OS之間復制數據包內容的麻煩,但是這麼做必須要求在網絡接口中接收緩沖隊列中的有頁對齊的區域(//因為這麼做是直接以頁框為單位進行的,所以一次交換就是一頁的內容,所以需要提供頁對齊的緩沖區域才可以進行)。當一個數據包被接收,Xen立即檢查接收規則組來確定目的VIF,然後將數據包緩沖區和相應的接收環(//接收環存在於各個domain中)交換一個頁框。如果這時沒有頁框可用的話,數據包就被丟棄。
3.3.6 磁盤
只有Domain 0能夠不經檢查地直接訪問物理(IDE和SCSI)磁盤。所有其它的domain訪問永久性存儲介質的時候,都要通過虛擬塊設備(VBD)抽象。這個抽象是由運行在Domain 0中的管理軟件來創建和配置的。由Domain 0管理VBD使得Xen中的機制比較簡單,不避使用更復雜的解決方案(比如Exokernel中使用的UDF[23])。
一個VBD是由一些和所有權以及訪問控制信息相關的擴展組成的,可以通過I/O環機制來訪問。一個典型的guest OS磁盤調度算法將重新排定請求的優先級並把它們排進環中,這樣做是為了盡量減少響應時間,並且可以有區別地進行服務(例如,由於進行投機的向前讀請求的代價很高,調度器可能會選擇主動先去調度後面的對同步數據的訪問請求)。另外,因為Xen對真實的磁盤規劃具有更完整的認識,所以我們也要在Xen中支持重新定序(//剛剛提到的是guest OS),並且可以亂序地返回響應。因此,對於guest OS來說,VBD有一點像SCSI磁盤。
在hypervisor內部還為每個VBD維護了一個轉換表;整個表中的內容都由Domain 0通過特權控制接口進行安裝和管理。在接收到一個磁盤請求後,Xen檢查VBD標識符和偏移,並且產生相應的扇區地址和所屬物理設備。許可檢查也是在這個時候進行的(//檢查到底能不能進行這個磁盤操作)。零復制數據傳遞將以DMA的方式在磁盤和綁定到該發出請求的domain上的內存頁之間進行。
Xen會使用簡單的循環輪轉方式來成批處理各個存在競爭關系的domain發出的請求;然後,在到達磁盤硬件之前,這些請求傳給標准的電梯調度器。domain可以顯式地設置重定序障礙(//不許重定序)來防止在必須維持高層次語義的時候(例如,在使用了一個預寫日志(write-ahead log)的時候)進行重定序。當成批的請求中能夠顯現出訪問的公平性的時候,低層的調度能夠給我們帶來很好的吞吐量。下一步工作將研究使用現有的技術和調度器提供更可預測的隔離性和支持更有差別的設備。
3.4建立新的Domain
為一個新的domain建立初始的guest OS結構,這個任務很大程度上是委托給Domain 0完成的。Domain 0使用它的特權控制接口(2.3段)訪問新的domain的存儲空間並告知Xen該新domain的初始寄存器狀態。這個方法相對於由Xen建立整個domain來說有一些優勢,包括減少了hypervisor的復雜度,改進了魯棒性(對特權接口的訪問要經過完全地檢查的,使得我們能夠在初始階段捕捉到大部分的bug。
最重要的是,整個建立過程易於被擴展,可以應付新的guest OS。例如,Linux內核引導時的地址空間是要比Windows XP簡單得多的。我們可以為所有的guest OS指定一個固定的初始內存規劃,但是這樣的話就需要針對每個guest OS編寫額外的引導陷阱代碼用來安置操作系統所需的其它部分。不幸的是,這類代碼是非常難以實現的;為了獲得簡單性和魯棒性,更好的實現方法就是使用Domain 0,它能夠提供比引導程序更充裕的診斷和調試支持。
Scatter-gather DMA方式是與block DMA方式相對應的一種DMA方式。
在DMA傳輸數據的過程中,要求源物理地址和目標物理地址必須是連續的。但是在某些計算機體系中,如IA架構,連續的存儲器地址在物理上不一定是連續的,所以DMA傳輸要分成多次完成。
如果在傳輸完一塊物理上連續的數據後引起一次中斷,然後再由主機進行下一塊物理上連續的數據傳輸,那麼這種方式就為block DMA方式。Scatter-gather DMA方式則不同,它使用一個鏈表描述物理上不連續的存儲空間,然後把鏈表首地址告訴DMA master。DMA master在傳輸完一塊物理連續的數據後,不用發起中斷,而是根據鏈表來傳輸下一塊物理上連續的數據,直到傳輸完畢後再發起一次中斷。
很顯然,scatter-gather DMA方式比block DMA方式效率高。
4.相關工作
虛擬化技術被應用在商業化和研究型操作系統上已經有近30年了。IBM VM/370[19,38]最先使用了虛擬化技術以提供對先前存留的代碼的支持。VMware[10]和Connectix[8]采用了將常用的PC硬件進行虛擬化的方法,允許多個操作系統在同一台主機上運行。所有這些例子都對底層硬件(至少是底層硬件的一個子集)進行了完全虛擬化的實現,而並非是准虛擬化的方法提供給guest OS一個修改後的接口。正如我們的評估結果中給出的:完全虛擬化雖然能夠更容易地支持商業市售的操作系統,但是卻大大降低了性能。
VMM方法還被Disco用於將常用的操作系統高效地運行在ccNUMA機器上[7,18]。其間要對被操控的操作系統做少量的改動,以使其能夠虛擬化地運行在MIPS體系結構上。另外,出於性能的考慮,還要做一些其它修改。
現在,我們知道有兩個其它的系統也采用了准虛擬化的方法:IBM不久前提出的Linux的准虛擬化版本允許大量的Linux實例同時運行,將用於他們的zSeries大型機上。Denali[44]在之前已經討論過,它是一個暫時隔離的內核,試圖提供能夠操控大量虛擬操作系統實例的系統能力。
除了Denali,我們還知道有兩種其它的方法使用了低層虛擬化技術建立分布式系統的底層架構。vMatrix[1]是基於VMware的,它的目標是建立一個用於在不同機器間移動代碼的平台。由於vMatrix是在VMware之上開發的,因此它更關注的是虛擬化技術在分布式環境中存在的高層問題。另外,在IBM提出的“托管管理(Managed Hosting)”服務中,虛擬Linux的實例可以在IBM大型機上被租用(//大型機上跑多個Linux實例,你可以租一個用,搭建你自己的系統,和其他租戶共享大型機的資源)。
PlanetLab項目[33]構建了一個分布式的底層架構,它的設計目的是作為實驗床用於研究和開發地理空間分布的網絡服務。平台的對象是研究者,試圖將單個的物理主機劃分為條(sliver),提供同時的對用戶的低層訪問。項目當前使用的是VServers[17]和SILK[4]來管理操作系統內部的共享。
我們再和操作系統外延研究和主動網絡通信研究中的一些思路作比較。當代碼在Xen上面運行的時候沒有必要檢查其“安全性”,也沒有必要去檢查代碼運行是否能夠保證終止,因為在這些情況中唯一的受害人是那些可疑的客戶。於是Xen提供了更通用的方案:這個方案不需要由一個可信的編譯器為被操控的代碼做數字簽名(比如SPIN[5]),不需要這些代碼被一個安全證明伴隨(比如PCC[31]),不需要由一種特殊的語言寫成(比如SafetyNet[22]或者其它基於Java的系統),也不需要依賴於特殊的中間件(比如移動代理(mobile-agent)系統)。當然,這些其它的技術能夠繼續在運行在Xen上的guest OS中使用,而且可能會對那些時限更短暫的任務負載有著特別的用途,因為這類任務沒有機會被成批處理以減少啟動一個新的domain的代價。(//這段的意思,我的感覺是在操作系統外延研究和主動網絡通信研究為了保證代碼安全,采用了多種多樣的方法;但是在Xen中,這些方法都是不必要的,因為Xen的安全性確認策略比較簡單,前文有提及;但是這些方法在Xen中也還是有它們的作用,比如對於時限短暫的任務,它等不及成批地被確認,那麼它就需要用其它方法保證安全性。)
關於語言級虛擬機(//比如Java虛擬機)方法中也存在著類似的問題:一個管理資源(resource-managed)的JVM[9]肯定能夠操控不可信的應用,前提是這些應用必須被編譯為Java字節碼並且遵循特別的系統安全模型(//不可信的代碼,即使出了問題,但是由於其遵循系統安全模型,所以也不會造成危害)。這樣的話,Xen就能夠容易地支持語言級虛擬機,就像支持其它運行在guest
OS上的應用一樣。(//這段的意思,和前面類似,仍舊是表明Xen並不提供過多的安全性檢查;如果要跑語言虛擬機之類的應用,語言的安全性要由虛擬機應用本身保證,而不關系到Xen。)
5.討論和結論
我們在上文介紹了Xen hypervisor。它能夠將計算機的資源劃分給各個運行著guest
OS的domain。我們的准虛擬化設計特別強調了性能和資源管理。我們還描述和評估了XeonLinux,XeonLinux是將Linux 2.4內核向Xen上做的完全移植。
5.1 Future Work — 將來的工作
我們認為Xen和XenoLinux完全能夠被用於更廣闊的空間,所以我們准備在不久的將來把我們的軟件做成一個公開版本。當前已經有一個Beta版本正在被評估(//貌似就是那個Clarkson University做的工作);一旦評估階段結束,我們就會在項目主頁上發布1.0版。
在完成初始版本後,我們計劃對Xen做一些的擴展和改進。為了增加虛擬塊設備的效率,我們准備實現一個由塊內容索引的共享的通用緩沖Cache(universal buffer cache)。這將為我們的設計增加受控的數據共享,同時卻不犧牲隔離性。為虛擬塊設備增加寫復制(copy-on-write)語義,使它們能夠在domain之間被安全地共享,即使是不同的文件系統也不會有問題(//寫復制,保證一致性,減少內容復制開銷;不過跨文件系統應該還是不很容易吧?)。
為了提供更好的physical(//物理?還是像之前提到的是“實際分得的”?應該是後者)內存性能,我們計劃實現一個最後機會頁緩存(LPC:last-chance page cache)。這是一個全系統范圍內的空閒頁鏈表,只有在機器內存未被分光的情況下,鏈表才有非零的長度。當guest OS虛擬存儲系統選擇捨棄一個干淨(clean:數據中沒有dirty data,都是與磁盤中相同的)的頁時會使用到LPC;這個干淨的頁會被加入到空閒鏈表的結尾,而並非被完全拋棄。如果在該頁重新被Xen分配之前發生了和該頁相關的錯誤,那麼對錯誤的處理是不需要磁盤訪問的(我的理解是,以往的方法如果操作系統釋放了內存資源的話,那麼它如果再想使用剛才釋放頁上的資源就必須重新從磁盤上調入;而現在的last-chance,就給了操作系統一個機會,如果出現了和剛釋放掉的頁內容相關的錯誤,那麼操作系統可以直接從這個LPC中調相關頁,而不用訪問磁盤)。
Xen的一個重要角色是作為XenoServer的基礎。XenoServer的設計目標超越了單機的范疇,它要搭建的是支持一個互聯網規模計算架構所必需的控制系統。對於我們的設計來說,關鍵在於資源的使用要被精確地計算並且由工作的發起者想辦法滿足資源需求 — 如果資源必須要及時兌現,我們就使用一個擁塞定價策略來處理那些超過資源提供能力的要求,使用透支的方法滿足超出的需求。這就必須要有精確、及時的I/O調度,它要能夠更有彈性地處理那些不友好(//惡意透支?)的工作負載。我們還計劃創建虛擬塊設備租借等形式,將會計學中的一些理論(//上述的租借,透支之類的概念都是屬於會計學的范疇)借鑒進我們的塊存儲架構中。
為了能夠為XenoServer的管理和經營提供更好的支持,我們正在加入對日志審核和日志鑒證更徹底的支持。我們還在開發其它的VFR規則,希望這些規則能夠使我們檢測和防止更大范圍的對社會有危害的網絡行為。最終,我們正在繼續我們在XenoXP上的工作,最重要的工作就是編寫網絡和塊設備驅動實例,工作的目標是完全支持企業級的服務器應用(如IIS)。
5.2結論
Xen提供了一個優秀的平台,在這個平台上能夠配置廣泛的多樣化的以網絡為中心的服務,比如動態web內容的局部鏡像,媒體流的編碼轉換和分發,多用戶游戲和虛擬現實服務器,還有為瞬時連接設備提供短暫網絡連接的“智能代理”[2]服務。
Xen直接解決的是在部署服務時遇到的最大障礙,即當前不能夠在低實例化開銷的前提下,對瞬時服務器操控較短的時間(//瞬時服務器:時有時無,有時候需要有時候不需要;而即使是每次需要,也只是操作很短的時間,馬上就又不需要了;所以這樣的話,頻頻切換,就需要很大的實例化開銷,因為每次啟動瞬時服務,就要實例化一次;但是Xen中,反正我可以跑多個系統,那就專門留一個或幾個系統給你跑瞬時服務,同時還不耽誤我其它服務的性能)。通過允許100個操作系統運行在單台服務器上,我們減少了兩個數量級的相關開銷。更進一步的,我們可以把對每個操作系統進行設定和配置的過程轉變為軟件行為,這樣就能夠更容易地操控更細粒度的時間片。
正如我們在第4部分給出的實驗結果,在Xen上運行XenoLinux的性能幾乎與本地Linux系統的性能相同。之所以會有這樣的結果,主要得益於對兩個部件之間接口(//就是VMM吧?操作系統和底層硬件兩個部分之間的接口)的細致設計,這使得我們幾乎感覺不到在使用資源管理工具時帶來的開銷。我們的下一步工作是移植BSD和Windows
XP的內核到Xen上來驗證Xen提供的接口的普適性。