KylinX:A Dynamic Library Operating System for Simplified and Efficient Cloud Virtualization
正文之前
彷彿好久沒寫過東西了。。剛才一翻,最新文章在1-19,三個月了。。。果然我已經快放棄簡書了,不過這兒好歹承載了那麼多的回憶,還是別丟了吧。以後把我翻譯的一些論文丟上來算了。。

正文
原文我都用CAJviewer識別出來,並且整理過了,有需要的請私信我 或者發我 郵箱 :[email protected] 詢問好了。下面我只放中文的內容了,(全篇大部分google翻譯,然後人讀一遍粗略修改過。有些地方可能還是不太通順,不過那就基本代表我也不大懂了。。。)裡面還有一些【】裡面的內容是我自己做的標註,可以忽略
Unikernel專門簡化LibOS和目標應用到一個獨立的單一用途的虛擬機器(VM)上執行在Hypervisor上,這被稱為(虛擬)裝置。 與傳統VM相比,Unikernel裝置具有更小的記憶體佔用和更低的開銷,同時保證了相同的隔離級別。 在缺點方面,Unikernel剝離了其整體裝置的流程抽象,從而犧牲了靈活性,效率和適用性。
本文探討了Unikernel裝置(強隔離)和流程(高靈活性/高效率)的最佳平衡。 我們提供KylinX,一個動態庫作業系統,通過提供pVM(類似程序的VM)抽象,實現簡化和高效的雲虛擬化。 pVM將虛擬機器Hypervisor作為作業系統,將Unikernel裝置作為允許頁面級和庫級動態對映的程序。
- 在頁面級別,KylinX支援pVM fork以及一組用於pVM間通訊(IpC)的API。
- 在庫級別,KylinX支援在執行時連結到Unikernel裝置的共享庫。
KylinX對潛在威脅實施對映限制。 KylinX可以在大約1.3毫秒內分叉pVM,並在幾毫秒內將庫連結到正在執行的pVM,兩者都與Linux上的程序分支相當(大約1毫秒)。 KylinX IpC的延遲也與UNIX IPC的延遲相當。
1 介紹
商品雲(如EC2 [5])提供了一個公共平臺,租戶租用虛擬機器(VM)來執行他們的應用程式。 這些基於雲的VM通常專用於特定的線上應用程式,如大資料分析[24]和遊戲伺服器[20],並被稱為(虛擬)裝置[56,64]。 高度專業化的單一用途裝置只需要傳統作業系統支援的一小部分來執行其容納的應用程式,而當前的通用作業系統包含廣泛的庫和功能,形成最終多使用者,多應用程式場景。裝置的單一用途的使用和傳統作業系統的通用設計之間的失配引起的效能和安全性懲罰,使基於裝置的服務的部署和安排變得繁瑣[62,52],執行效率低[56],並容易受到不必要的庫的影響[27]。
這個問題最近推動了Unikernel [56]的設計,這是一個庫作業系統(LibOS)架構,旨在實現雲中高效安全的裝置。 Unikernel將傳統作業系統重構為庫,並將應用程式二進位制和必需庫封裝成專用的應用映象,該映像可直接在 Xen [ 30]和KVM [22] 等虛擬機器Hypervisor上執行。與傳統VM相比,Unikernel裝置去掉了未使用的程式碼:
- 實現了更小的記憶體佔用
- 更短的啟動時間
- 更低的開銷
- 同時保證了相同的隔離級別。
虛擬機器Hypervisor的穩定介面避免了早期LibOS遇到的硬體相容性問題[39]。
【Mark: 早期LibOS可以一看】
在缺點方面,Unikernel剝離了其靜態密封的單片裝置的過程提取,因此犧牲了靈活性,效率和適用性。 例如,Unikernel不能支援動態fork,這是傳統UNIX應用程式常用的多程序抽象的基礎; 並且編譯時導致的不可變性使得執行時無法管理,例如線上庫更新和地址空間隨機化。 這種缺陷在很大程度上降低了Unikernel的適用性和效能。
【 在多工作業系統中, 程序 (執行的程式)需要一種方法來建立新程序,例如執行其他程式。Fork及其變種在類Unix系統中通常是這樣做的唯一方式。如果程序需要啟動另一個程式的可執行檔案,它需要先Fork來建立一個自身的副本。然後由該副本即“ 子程序 ” 呼叫 exec 系統呼叫,用其他程式覆蓋自身:停止執行自己之前的程式並執行其他程式。
Fork 操作會為子程序建立一個單獨的 地址空間 。子程序擁有父程序所有記憶體段的精確副本。在現代的UNIX變種中,這遵循出自SunOS-4.0的 虛擬記憶體 模型,根據 寫入時複製 語義,實體記憶體不需要被實際複製。取而代之的是,兩個程序的 虛擬記憶體頁面 可能指向 實體記憶體 中的同一個頁,直到它們寫入該頁時,寫入才會發生。在用fork配合exec來執行新程式的情況下,此優化很重要。通常來說,子程序在停止程式執行前會執行一小組有利於其他程式的操作,它可能用到少量的其父程序的 資料結構 。
當一個程序呼叫fork時,它被認為是 父程序 ,新建立的程序是它的孩子(子程序)。在fork之後,兩個程序還執行著相同的程式,都像是呼叫了該系統呼叫一般恢復執行。然後它們可以檢查呼叫的 返回值 確定其狀態:是父程序還是子程序,以及據此行事。
fork 系統呼叫在第一個版本的Unix就已存在 [1] ,它借用於更早的 GENIE 分時系統 。 [2] Fork 是標準化的 POSIX 的一部分 】
在本文中,我們將研究是否存在平衡,以獲得Unikernel裝置(強隔離)和程序(高靈活性/高效率)的最佳效能。在虛擬機器Hypervisor(Hypervisor)上的應用程式和傳統作業系統上的程序之間進行類比,從靜態Unikernel向前邁出一步,就有了KylinX,這是一個動態庫作業系統,通過提供pVM(process-like VM)抽象來實現簡化和高效的雲虛擬化。 我們將虛擬機器Hypervisor作為作業系統和允許pVM的頁級和庫級動態對映的程序一樣的應用程式。
【Hypervisor,又稱虛擬機器器監視器(英語:virtual machine monitor,縮寫為 VMM),是用來建立與執行 虛擬機器器 的軟體、韌體或硬體。
被Hypervisor用來執行一個或多個虛擬機器器的電腦稱為主體機器(host machine),這些虛擬機器器則稱為客體機器(guest machine)。hypervisor提供虛擬的作業平臺來執行客體作業系統(guest operating systems),負責管理其他客體作業系統的執行階段;這些客體作業系統,共同分享虛擬化後的硬體 資源 。】
- 在頁面級別,KylinX支援pVM fork和一組用於inter-pVM communication(IpC)的API,它與傳統的UNIX程序間通訊(IPC)相容。 IpC的安全性通過僅允許從同一個根pVM分叉的相互受信任的pVM之間的IpC得到保證。
- 在庫級別,KylinX支援共享庫,動態連結到Unikernel裝置,使pVM能夠執行(i)線上庫更新,在執行時將舊庫替換為新庫,以及(ii)重用記憶體域以進行快速啟動。 我們分析動態對映引發的潛在威脅並實施相應的限制。
我們通過修改MiniOS [14](用C編寫的Unikernel LibOS)和Xen'stoolstack實現了基於Xen [30](1型Hypervisor)的KylinX原型。 KylinX可以在大約1.3毫秒內分配pVM,並在幾毫秒內將庫連結到正在執行的pVM,這兩者都與Linux上的程序分支相當(大約1毫秒)。 KylinX IpC的延遲也與UNIX IPC相當。對實際應用程式(包括Redisserver [13]和Web伺服器[11])的評估表明,Kylin在保留隔離保證的同時,比靜態Unikernel具有更高的適用性和效能。
本文的其餘部分安排如下。 第2節介紹了背景和設計選項。第 3 節介紹了具有安全限制的動態定製的KylinX LibOS的設計 。 第4節報告了KylinX原型實現的評估結果。 第5節介紹相關工作。 第6節總結了論文並討論了未來的工作。
2 背景
2.1 VM ,容器和Picoprocesses
虛擬化和隔離的文獻中有幾種傳統模型:程序,Jails和VM。
- OS程序。 程序模型是針對傳統的(部分信任)作業系統環境,並提供豐富的ABI(應用程式二進位制介面)和互動性,使得它不適合真正的交付給租戶。
- FreeBSD Jails [47]。 jail模型提供了一種輕量級機制來分離應用程式及其相關策略。它在傳統作業系統上執行一個程序,但限制了幾個系統呼叫介面以減少漏洞。
- VMs。 VM模型構建隔離邊界匹配硬體。 它為guest虛擬機器提供了執行完整作業系統的傳統相容性,但對於重複和殘留的作業系統元件而言,這是非常昂貴的。

虛擬機器(圖1(左))已被廣泛用於多租戶雲, 因為它保證了強大的(型別-監督)隔離[55]。 但是,VM的當前虛擬化體系結構非常繁重,包括高階Hypervisor,VM,OS核心,程序,語言執行時( 如glibc [16]和JVM [21]),庫和應用程式,它們很複雜,無法再滿足商業雲的效率要求。
容器(如LXC [9]和Docker [15])利用核心功能來打包和隔離程序。他們最近需求量很大[25,7,6],因為與VM相比它們很輕。但是,容器比在隔離性上比VM更弱,因此它們經常在VM中執行以實現適當的安全保障[58]。
【 Docker容器實現原理及容器隔離性踩坑介紹: http://dockone.io/article/8148 】
Picoprocesses [38](圖1(中))可以被視為具有更強隔離性但更輕量級的容器。他們使用主機作業系統和客戶機之間的小型介面來實現LibOS,實現主機ABI並將高階客戶機API對映到小介面。 Picoprocesses特別適合客戶端軟體交付,因為客戶端軟體需要在各種主機硬體和作業系統組合上執行[38]。它們也可以在hvpervisors上執行【62,32】。
最近對picoprocesses的研究[67,32,54] 通過允許dynamics來重新啟動原始靜態隔離模型。 例如,Graphene [67]支援picoprocess fork和multi-picoprocess API,而Bascule [32]允許OS-independent擴充套件附加到執行時的picoprocess。 雖然這些鬆弛會稀釋嚴格的隔離模型,但它們有效地將picoprocesses的適用範圍擴充套件到更廣泛的應用範圍。
2.2 Unikernel Appliances
基於程序的虛擬化和隔離技術面臨來自用於與主機作業系統互動的廣泛核心系統呼叫API的挑戰。例如,程序/執行緒管理,IPC,網路等.Linux系統呼叫已達到近400 [3]並且是不斷增加,並且系統呼叫API比VM的ABI( 可以利用硬體記憶體隔離和CPU環) 更難以保護 [58]。
最近,研究人員提出減少VM,而不是增加程序,以實現安全和高效的雲虛擬化。Unikernel [56]專注於單應用程式VM裝置[26],並將Exokernel [39]樣式的LibOS應用於VM guest虛擬機器,以提高效能優勢,同時保留1類虛擬機器Hypervisor的強隔離保證。它打破了傳統的通用虛擬化架構(圖1(左)),並將OS功能(例如,裝置驅動程式和網路)實現為庫。與其他基於Hypervisor的簡化虛擬機器(如Tiny CoreLinux [19]和OS 0 [ 49])相比,Unikernel僅將應用程式及其必需的庫封裝到映象中。
【Mark:Exokernel is an operating system kernel developed by the MIT Parallel and Distributed Operating Systems group,[1] and also a class of similar operating systems.
Operating systems generally present hardware resources to applications through high-level abstractions such as (virtual) file systems. The idea behind exokernels is to force as few abstractions as possible on application developers, enabling them to make as many decisions as possible about hardware abstractions.[2] Exokernels are tiny, since functionality is limited to ensuring protection and multiplexing of resources, which is considerably simpler than conventional microkernels' implementation of message passing and monolithic kernels' implementation of high-level abstractions.
Implemented applications are called library operating systems; they may request specific memory addresses, disk blocks, etc. The kernel only ensures that the requested resource is free, and the application is allowed to access it. This low-level hardware access allows the programmer to implement custom abstractions, and omit unnecessary ones, most commonly to improve a program's performance. It also allows programmers to choose what level of abstraction they want, high, or low.
Exokernels can be seen as an application of the end-to-end principle to operating systems, in that they do not force an application program to layer its abstractions on top of other abstractions that were designed with different requirements in mind. For example, in the MIT Exokernel project, the Cheetah web server stores preformatted Internet Protocol packets on the disk, the kernel provides safe access to the disk by preventing unauthorized reading and writing, but how the disk is abstracted is up to the application or the libraries the application uses. https://en.wikipedia.org/wiki/Exokernel 】
l 【型別I:本地或裸機Hypervisor
l 型別II:Hosted Hypervisor】
由於Hypervisor已經提供了傳統作業系統的許多管理功能(例如隔離和排程) ,因此Unikernel採用了(minimalism philosophy)極簡主義哲學[36],它不僅通過刪除不必要的庫而且還從其LibOS中剝離了重複的管理功能來最小化VM。 例如,Mirage[57]遵循多核模型[31]並利用虛擬機器Hypervisor進行多核排程,使單執行緒執行時可以具有快速的順序效能; MiniOS [14]依賴於Hypervisor( 而不是in-LibOS連結器)來載入/連結裝置啟動時間; 而LightVM [58]通過重新設計Xen的控制平面實現了快速VM啟動。
2.3 動機和設計選擇
Unikernel裝置和傳統的UNIX程序可以抽象出隔離,特權和執行狀態的單元,並提供記憶體對映,執行協作和排程等管理功能。為了實現低記憶體佔用和小型計算基礎(TCB),Unikernel剝離了其單片裝置的程序抽象,並將簡約LibOS與其目標應用程式相連結,展示了依靠虛擬機器Hypervisor消除重複功能的好處。但在缺點方面,程序和編譯時確定的整體性大大降低了Unikernel的靈活性,效率和適用性。
【TCB是Trusted Computing Base的簡稱,指的是計算機內保護裝置的總體,包括硬體、 韌體 、軟體和負責執行 安全策略 的組合體。它建立了一個基本的保護環境並提供一個 可信計算機系統 所要求的附加使用者服務。】
如圖1(右)所示,KylinX通過將虛擬機器Hypervisor顯式為一個OS,而將Unikernel裝置作為程序顯式提供pVM抽象。 KylinX輕鬆放鬆了Unikernel的編譯時單片性要求,允許頁面級和庫級動態對映,這樣pVM就可以擁有Unikernel裝置和UNIX程序的最佳效能。如表1所示,KylinX可以被視為對Unikernel的擴充套件(提供pVM抽象),類似於Graphene [67](提供傳統的多工藝相容性)和 Bascule [ 32](提供執行時可擴充套件性)的擴充套件到picoorocess。
出於以下原因,我們在Hypervisor而不是guestLibOS中實現KylinX的動態對映擴充套件。
-
首先,guestLibOS外部的擴充套件允許Hypervisor強制執行對映限制(第 3.2.3節和第3.3.3節),從而提高安全性。
-
其次,Hypervisor更靈活地實現動態管理,例如,在pVM的線上庫更新期間恢復實時狀態(第3.3.2節)。
-
第三,KylinX很自然地遵循Unikernel的極簡主義哲學(第2.2章),利用虛擬機器Hypervisor來消除重複的客戶LibOS功能。
向後相容性是另一種權衡。 最初的Mirage Unikernel [56]佔據了一個極端的位置,現有的應用程式和庫必須在OCaml [10]中完全重寫,以確保型別安全,這需要大量的工程工作,並可能引入新漏洞。 相比之下,KylinX旨在支援原始碼(主要是C)相容性,因此可以在KylinX上執行各種各樣的遺留應用程式,只需最少的調整工作。

威脅模型。 KylinX採用傳統的威脅模型[56,49],與Unikernel相同的上下文[ 56],其中 VM/pVM 在虛擬機器Hypervisor上執行,並且有望在公共多租戶雲中提供面向網路的服務。 我們假設攻擊者可以在VM/pVM中執行不受信任的程式碼,並且在VM/pVM中執行的應用程式受到來自同一雲中的其他人和來自通過Internet連線的惡意主機的潛在威脅。KylinX將虛擬機器Hypervisor(使用其工具堆疊)和控制域(dom0)視為TCB的一部分,並利用虛擬機器Hypervisor隔離其他租戶的攻擊。使用SSL和SSH等安全協議有助於KylinX pVM對外部實體進行信任。
【 https://www.ibm.com/developerworks/cn/cloud/library/cl-hypervisorcompare/index.html
------------------------------------------------------------------------------
Dom0 is the initial domain started by the Xen hypervisor on boot. Dom0 is an abbrevation of "Domain 0" (sometimes written as "domain zero" or the "host domain"). Dom0 is a privileged domain that starts first and manages the DomU unprivileged domains. The Xen hypervisor is not usable without Dom0
A DomU is the counterpart to Dom0 ; it is an unprivileged domain with (by default) no access to the hardware. It must run a FrontendDriver for multiplexed hardware it wishes to share with other domains. A DomU is started by running 】
英特爾軟體Guard eXtensions(SGX)[12]等硬體的最新進展證明了遮蔽執行的可行性,並以保護VM/pVM免受特權虛擬機器Hypervisor和dom0 [33,28,45]破壞的可行性,這將在我們未來的工作中進行研究。 我們還假設硬體裝置沒有受到損害,儘管已經確定了硬體威脅[34]。
3 KylinX 設計
3.1概述
KylinX擴充套件了Unikernel,以實現以前僅適用於程序的理想功能。我們不是從零開始設計一個新的LibOS,而是基於MiniOS構建KylinX [27],這是一個在Xen虛擬機器Hypervisor上執行的使用者VM域(domU)的C風格Unikernel LibOS. MiniOS 使用其前端驅動程式訪問硬體,連線到相應的硬體特權dom0或專用驅動程式域中的後端驅動程式.MiniOS具有單個地址空間,沒有核心和使用者空間分隔,也沒有搶佔的簡單排程程式。 MiniOS很小巧但適合在Xen上採用整潔高效的LibOS設計。 例如,Erlang on Xen [1],LuaJIT [2],C1ickOS [59]和LightVM [58]分別利用MiniOS提供 Erlang,Lua ,Click和快速啟動環境。
【Marked:Xen虛擬化基本原理詳解 https://blog.51cto.com/wzlinux/1727106
Mini-OS: https://wiki.xenproject.org/wiki/Mini-OS-DevNotes 】
如圖2所示,基於MiniOS的KylinX設計包括(i)DomO中Xen工具堆疊的(受限制的)動態頁面/庫對映擴充套件,以及(ii)程序抽象支援(包括動態pVMfork/IpC和執行時pVM)庫連結)在DomU。

3.2 動態頁面對映
KylinX通過利用Xen的共享記憶體和授權表來執行跨域頁面對映,從而支援程序式裝置分支和通訊。
3.2.1 pVM Fork
fork API是實現pVM傳統多程序抽象的基礎。 KylinX將每個使用者域(pVM)視為一個程序,當應用程式呼叫fork()時,將生成一個新的pVM。
我們利用Xen的記憶體共享機制實現fork操作,它通過
(i)複製xc_dom_image結構
(ii)呼叫Xen的unpause()API來分叉呼叫父pVM並將其域ID返回給父級來建立child pVM。

如圖3所示,當在父pVM中呼叫fork() 時,我們使用內聯彙編來獲取CPU暫存器的當前狀態並將它們傳遞給子暫存器。控制域(dom0)負責分支和啟動子pVM。 我們修改libxc以在建立父pVM時將xc_dom_images結構保留在記憶體中,這樣當呼叫fork()時,結構可以直接對映到子pVM的虛擬地址空間,然後父程序可以使用授權表與子程序進行共享。以可寫資料以寫時複製(CoW)方式共享。
【Copy-on-write (CoW or COW), sometimes referred to as implicit sharing[1] or shadowing,[2] is a resource-management technique used in computer programming to efficiently implement a "duplicate" or "copy" operation on modifiable resources.[3] If a resource is duplicated but not modified, it is not necessary to create a new resource; the resource can be shared between the copy and the original. Modifications must still create a copy, hence the technique: the copy operation is deferred to the first write. By sharing resources in this way, it is possible to significantly reduce the resource consumption of unmodified copies, while adding a small overhead to resource-modifying operations.
如果資源重複但未修改,則無需建立新資源; 資源可以在副本和原始檔案之間共享。 修改必須仍然建立一個副本,因此技術:複製操作被推遲到第一次寫入。 通過以這種方式共享資源,可以顯著減少未修改副本的資源消耗,同時為資源修改操作增加一小部分開銷
https://en.wikipedia.org/wiki/Copy-on-write 】
通過unpause()啟動子pVM之後,它(i)接受來自其父級的共享頁面,(ii)恢復CPU暫存器並跳轉到fork之後的下一條指令,以及(iii)開始作為子級執行。在完成fork()之後 ,KylinX非同步初始化一個事件通道並在父子pVM之間共享專用頁面以啟用它們的IpC,如下一小節中所介紹的。
3.2.2 inter-pVM通訊(IpC)
KylinX提供了一個多程序(多pVM)應用程式,其所有程序(pVM)都在OS(Hypervisor)上協同執行。目前,KylinX遵循嚴格的隔離模型[67],其中只有相互信任的pVM才能相互通訊,這將在第3.2.3中詳細討論。
兩個通訊pVM使用事件通道共享頁面來實現pVM間通訊。如果兩個相互信任的pVM在第一次通訊時尚未初始化事件通道,因為它們沒有通過fork()產生的父子關係(3.2.1),那麼KylinX將:
- 驗證其相互適應性(第3.2.3節,必須是一個family的)
- 初始化事件通道
- 在它們之間共享專用頁面。
事件通道用於通知事件,共享頁面用於實現通訊。 KylinX已經實現了以下四種類型的inter-pVM通訊API(在表2中列出)。
- (1)pipe(fd)建立一個管道並返回兩個檔案描述符(fd [0]和fd [1]),一個用於寫入,另一個用於讀取。
- (2)kill( domid,SIG )通過將SIG寫入共享頁面並通知目標pVM(domid)從該頁面讀取訊號,將訊號(SIG)傳送到另一個pVM(domid); exit和wait是使用kill實現的。
- (3) ftok( path,projid)將path和proj id轉換為IpC金鑰,這將由msgget(key,msgflg)用於建立帶有標誌的訊息佇列(msgflg)並返回佇列ID(msgid); msgsend (msgid,msg,len)和msgrcv(msgid,msg,len)使用長度len寫入/讀取佇列(msgid)到/來自msmbuf結構(msg)。
- (4)shmget(key,size,shmflg)使用鍵(key),記憶體大小(size)和flag(shmflg)建立並存儲一個記憶體區域,並返回共享記憶體區域ID(shmid),它可以附加和分離到shmat(shmid,shmaddr,shmflg)和shmdt(shmaddr)。

3.2.3 動態頁面對映限制
在執行動態pVM fork時,父pVM將頁面分享給空的子pVM ,該過程不會引入新的威脅。
在執行IpC時,KylinX通過抽象相互信任的pVM 來保證安全性,這些pVM是從同一個根pVM分叉的。例如,如果pVM A分支pVM B,它進一步分叉另一個pVM C,那麼三個pVM A,B和C屬於同一個家庭。為簡單起見,目前KylinX遵循all-all-nothing隔離模型:只有屬於同一系列的pVM才被認為是可信的並且允許彼此通訊。 KylinX拒絕不受信任的pVM之間的通訊請求。
3.3 動態庫對映
3.3.1 pVM庫連結
繼承自MiniOS,KylinX具有單個平面虛擬儲存器地址空間,其中應用程式二進位制和庫,系統庫(用於載入程式,記憶體分配等)和資料結構共同定位以執行。 KylinX將一個動態段加入MiniOS的原始記憶體佈局中,以便在載入後適應動態庫。
如圖2所示,我們在Xen控制元件庫(libxc)中實現了動態庫對映機制,它由上層工具棧使用,例如xm/xl/chaos。 pVM實際上是一個準虛擬化domU,它
- 建立一個域,
- 解析kernel image檔案
- 初始化啟動記憶體,
- 在記憶體中構建映像
- 啟動映像的domU。

在上面的第4步中,我們通過擴充套件libxc的靜態連結過程,新增一個函式(xc_dom_map_dyn())來將共享庫對映到動態段中,如下所示。
- 首先 ,KylinX從裝置映像的程式頭表中讀取共享庫的地址,偏移量,檔案大小和記憶體大小。
- 第二 ,它驗證是否滿足限制(第3.3.4節KylinX強制限制庫的身份以及庫的載入器)。 如果不是,則程式終止。
- 第三 ,對於每個動態庫,KylinX檢索其 動態部分的資訊,包括動態字串表,符號表等。
- 第四 ,KylinX將整個依賴樹中的所有必需庫對映到pVM的動態段,當實際訪問時,它將惰性地將未解析的符號重定位到正確的虛擬地址。
- 最後 ,它跳轉到pVM的入口點。
KylinX在實際使用之前不會載入/連結共享庫,這類似於傳統程序的延遲繫結[ 17]。因此,KylinX pVM的啟動時間低於以前的Unikernel VM。 此外,與之前僅支援靜態庫的Unikernel相比,使用共享庫的KylinX的另一個優勢是它有效地減少了高密度部署中的記憶體佔用(例如,LightVM [58]中的每臺機器8K VM和每臺機器80K容器)在Flurries [71]中,這是限制可擴充套件性和效能的唯一最大因素[58]。
【Mark:動態連結和延遲繫結: https://www.jianshu.com/p/20faf72e0e9f 】
接下來,我們 將討論KylinX AVM的動態庫對映的兩個簡單應用。
3.3.2 線上 pVM庫更新
保持系統/應用程式庫的最新版本以修復錯誤和漏洞非常重要。 靜態Unikernel [56]必須重新編譯並重新啟動整個裝置映像才能為其每個庫應用更新 ,這可能會導致裝置擁有許多第三方庫時出現大量部署負擔。
線上庫更新比滾動啟動更有吸引力,主要是保持與客戶端的連線。首先,當伺服器有許多長期連線時,重新啟動將導致高重新連線開銷。其次,不確定第三方客戶端是否會重新建立連線,這會在重新啟動後為重新連線施加複雜的設計邏輯。第三,頻繁重啟和重新連線可能會嚴重降低關鍵應用程式的效能,如高頻交易。
動態對映使KylinX可以實現線上庫更新。 但是,庫可能有自己的狀態,例如壓縮或加密,因此簡單地替換無狀態函式不能滿足KylinX的要求。
像大多數庫更新機制(包括DYMOS [51],Ksplice [29],Ginseng [61],PoLUS [37 ],Katana [63],Kitsune [41]等),KylinX要求新舊庫與二進位制相容:允許向庫中新增新函式和變數,但不允許更改函式介面,刪除函式/變數或更改結構欄位。對於庫狀態,我們期望所有狀態都儲存為在更新期間將被儲存和恢復的變數(或動態分配的結構)。
KylinX提供了更新(domid,new_lib,old_lib)API,可以動態地將old_lib和new_lib替換為domU pVM(ID = domid),並具有必要的庫狀態更新。 我們還提供了一個更新命令“update domid,new_lib,old_lib” 用於解析引數並呼叫update() API。
動態pVM更新的難點在於在密封的VM裝置中操作符號表。 我們利用dom0來解決這個問題。 當呼叫更新API時,dom0將
(i)將新庫對映到dom0的虛擬地址空間;
(ii)與domU共享裝載的庫;
(iii)通過要求domU檢查domU的每個核心執行緒的呼叫堆疊來驗證舊庫是否靜止;
(iv)等到舊庫未被使用並暫停執行;
(v)將受影響的符號條目修改為適當的地址; 最後
(vi)釋放舊庫。 在上述第五步中,有兩種符號(函式和變數)將如下所述進行解析。
函式。 函式的動態解析過程如圖4所示。我們將重定位表,符號表和字串表儲存在dom0中,因為它們不在可載入段中。 我們在dom0中載入全域性偏移表函式(.got.plt )和過程連結表(.plt)並與domU共享它們。 為了在不同的域中解析符號,我們在.plt 表的第1st個條目中修改了2nd的彙編行 (如圖4中的藍色區域所示),以指向KylinX的符號解析函式(du_resolve)。 在載入新的庫(new_lib)之後,將old_lib中的每個函式輸入 .got.plt表(例如,圖4中的foo)被修改為指向.plt表中的相應條目,即圖4中虛線綠線所示的2nd元件(push n)。當一個函式(在new_lib載入後第一次呼叫庫的foo),將使用兩個引數( n (got + 4)) 呼叫du_resolve ,其中n是.got.plt表中符號(foo)的偏移量和 (got+ 4)是當前模組的ID。 然後du_resolve要求dom0呼叫對應的d0_resolve,它在new_lib中找到foo,並將當前模組的gt.plt表中的相應條目(由n定位)更新為foo的正確地址(圖中的藍線) 4)。
變數。 變數的動態解析度略微複雜。 目前我們只是假設new_libexpect將其所有變數設定為它們的實時狀態inold_lib而不是它們的初始值。 如果沒有這個限制,編譯器將需要擴充套件以允許開發人員為每個變數指定他們的意圖。
(1)全域性變數。 如果在主程式中訪問了庫的全域性變數(g),則g儲存在程式的資料段 (.bss )中,並且在指向g的庫的全域性偏移表(.got)中存在條目,因此載入new_lib後,KylinX會將new_lib的.got表中的g條目解析為g的正確地址。 否則,g儲存在庫的資料段中,因此KylinX負責將全域性變數g從old_lib複製到new_lib。
(2)靜態變數。 由於靜態變數儲存在庫的資料段中並且無法從外部訪問,因此在載入new_1 ib之後,KylinX將簡單地將它們從old_lib逐個複製到new_lib。
(3)指標。 如果庫指標(p)指向動態分配的結構,那麼KylinX會預先設定結構並將new_lib中的p設定為它。 如果p指向儲存在程式資料段中的全域性變數,那麼p將從old_lib複製到new_lib。 如果指向靜態變數(或儲存在庫中的全域性變數),則p將指向新地址。

3.3.3 pVM 回收
KylinX pVM和Unikernel VM [58]的標準啟動(第3.3.1節)相對較慢。 正如評估的第4章所述,啟動pVM或UnikernelVM需要100多毫秒,大部分時間用於建立空域。 因此,我們為KylinX pVM設計了一個pVM回收機制,利用動態庫對映來繞過域建立。
回收的基本思想是重用一個記憶體空域來動態地將應用程式(作為共享庫)對映到該域。 具體來說,在呼叫佔位符動態庫的app_entry函式之前,會檢查一個空的可回收的域並等待執行應用程式。使用app_entry作為條目,將應用程式編譯為共享庫而不是可引導映像。為了加速應用程式的pVM引導,KylinX恢復了被檢查的域,並通過在線上更新過程之後替換佔位符庫來連結應用程式庫(第3.3.2節)。
3.3.4 動態庫對映限制
與執行動態庫對映時靜態和單片密封的Unikernel相比,KylinX應該隔離任何新的漏洞。 主要的威脅是攻擊者可能會將惡意庫載入到pVM的地址空間,用具有相同名稱和符號的受損庫替換庫,或者將共享庫的符號表中的條目修改為偽符號/函式。
***【Linux程序地址空間學習: ***
http://www.choudan.net/2013/10/24/Linux%E8%BF%9B%E7%A8%8B%E5%9C%B0%E5%9D%80%E7%A9%BA%E9%97%B4%E5%AD%A6%E4%B9%A0 (%E4%B8%80).html******】
為了解決這些威脅,KylinX強制限制庫的身份以及庫的載入器。 KylinX支援開發人員指定動態庫的簽名,版本和載入器的限制,這些限制儲存在pVM映像的標頭中,並在連結庫之前進行驗證。
簽名和版本。庫開發人員首先生成庫的SHA1摘要,該摘要將由RSA(Rivest-Shamir-Adleman)加密。 結果儲存在動態庫的asignature部分中。 如果裝置需要對庫進行簽名驗證,則KylinX將使用公鑰讀取並驗證簽名部分。同樣要求並驗證版本限制。
裝載機。開發人員可以在庫的載入器上請求不同級別的限制:(i)僅允許pVM本身作為載入器; (ii)還允許同一申請的其他pVM; 或(iii)甚至允許其他應用程式的pVM。 通過前兩個限制,一個受損應用程式中的惡意庫不會影響其他應用程式。 載入程式檢查的另一種情況是將應用程式二進位制檔案作為庫並將其連結到pVM以進行快速回收(第3.3.3節),其中KylinX將載入程式限制為空pVM。
有了這些限制,與靜態密封的Unikernel相比,KylinX沒有引入任何新的威脅。 例如,pVM的執行時庫更新(第3.3.2節)對簽名(作為可信開發人員 ),版本 (作為特定版本號)和載入器(作為pVM本身)具有限制,將具有相同的級別安全保障重新編譯和重新啟動。
4 評估
我們在Ubuntu 16.04和Xen上實現了KylinX的原型。 按照MiniOS [14]的預設設定,我們分別使用RedHat Newlib和1wIP作為libc/libm庫和TCP/IP堆疊。我們的試驗檯有兩臺機器,每臺機器都配有Intel 6 core Xeon ES-2640 CPU,128 GB RAM和一臺1 Gb ENIC。
我們已經向KylinX移植了一些應用程式,其中我們將使用多程序Redis伺服器[13]以及多執行緒Web伺服器[11]在4.6章中來評估KylinX的應用程式效能。 由於MiniOS和RedHat Newlib的限制,目前需要進行兩種調整才能將應用程式移植到KylinX。 首先,KylinX只能支援select而不是更高效的epoll。 其次,程序間通訊(IPC)僅限於表2中列出的API。
4.1 標準啟動
我們評估 KylinX pVM 的標準啟動過程( 3.3.1)的時間,並將其與所有執行Redis伺服器的MiniOS VM和Docker容器進行比較。 Redis是一個記憶體中的鍵值儲存,支援快速鍵值儲存/查詢。 每個鍵值對由固定長度鍵和可變長度值組成。它使用單執行緒程序來提供使用者請求,並通過分配新的備份過程來實現(定期)序列化。
我們禁用Xen Store日誌記錄以消除定期日誌檔案重新整理的干擾。RedHat Newlib的C庫(libc)在嵌入式系統中是靜態的,很難轉換為共享庫。簡單來說,我們將libc編譯成靜態庫和libyn( Newlib的數學庫)到一個共享庫中,該庫將在執行時連結到KylinX pVM。由於Mini不能支援fork,我們(暫時)刪除此實驗中的相應程式碼。
啟動單個KylinX pVM大約需要124毫秒,可以大致分為兩個階段,即在記憶體中建立域/映像(步驟1~4,第3.2.1節),以及引導映像(步驟5)。動態對映在第一階段執行。大多數 時間(大約121毫秒)花費在第一階段,這會呼叫高階呼叫來與Hypervisor進行互動。第二階段啟動pVM大約需要3毫秒。在此相反,MiniOS大約需要133毫秒啟動一個虛擬機器,而Docker 需要花費約210毫秒開始建立容器。 KylinX比MiniOS花費的時間更短,主要是因為在引導期間不會讀取/連結共享庫。
然後,我們評估在一臺機器上順序啟動大量(最多1K)pVM的總時間。我們還評估了MiniOS VM和Docker容器的總啟動時間,以便進行比較。
結果如圖5所示。首先,由於延遲載入/連結,KylinX比MiniOS快得多。其次,MiniOS和KylinX的啟動時間隨著VM/pVM數量的增加而線性增加,而Docker容器的啟動時間只是線性增加,這主要是因為XenStore在服務大量的VM/pVM時效率很低。

4.2 fork和回收
與容器相比,由於XenStore效率很高,KylinX的標準啟動無法很好地擴充套件到大量pVM。最近,LightVM [58]通過實現chaos/libchaos,noxs(無XenStore)和拆分工具堆疊以及許多其他優化來完全重新設計Xen的控制平面,從而實現大量VM的ms級啟動時間。我們採用LightVM的nox來消除XenStore的影響,並測試執行未經修改的Redis模擬傳統程序分支的pVM fork機制。 LightVM的noxs使KylinX pVM的啟動時間即使對於大量pVM也能線性增加。單個pVM的fork大約需要1.3毫秒(未顯示缺少空間),比LightVM的原始啟動過程快幾倍(約4.5毫秒)。KylinX pVM 的fork比 Ubuntu上的程序fork(大約1 ms)略慢,因為包括頁面共享和引數傳遞在內的多個操作非常耗時。請注意,父/子pVM的事件通道和共享頁的初始化是非同步執行的,因此不計入fork的延遲。
4.3 記憶體佔用
我們在一臺機器上測量不同數量的pVM/VM/容器的KylinX,MiniOS和Docker(Running Redis)的記憶體佔用量。結果(如圖6所示)證明,與靜態密封的MiniOS和Docker容器相比,KylinX pVM具有更小的儲存空間。這是因為KylinX允許同一個應用程式( 第3.3章) 的所有裝置共享庫(libc除外),因此共享庫最多需要載入一次。記憶體佔用優勢促進了虛擬化[42],可用於在VM裝置之間動態共享實體記憶體,並使KylinX能夠實現與頁面級重複資料刪除[40]相當的記憶體效率,同時降低複雜性。

4.4 Inter-pVM通訊
我們通過分配父pVM並測量父/子通訊延遲來評估pVM間通訊(IpC)的效能。我們將一對父/子pVM稱為線性pVM。正如引言第3.2.1節所述,兩個線性pVM已經有一個事件通道共享頁面,因此它們可以直接與其他頁面進行通訊。相反,非線性pVM對必須在第一次通訊之前初始化事件通道和共享頁面。
結果列於表3中,我們將其與Ubuntu上相應的IPC進行比較。由於Xen的高效能事件通道和共享記憶體機制,兩個線性pVM之間的KylinX IpC延遲與Ubuntu上相應的IPC延遲相當。請注意,pipe的延遲不僅包括建立管道,還包括通過管道寫入和讀取值。由於初始化成本的原因,非線性pVM之間的首次通訊延遲要高出幾倍。

4.5 執行時庫更新
我們通過使用較新版本(RedHat Newlib 1.18)動態替換預設libyn(RedHat Newlib 1.16)來評估KylinX的執行時庫更新。libyn是MiniOS / KylinX使用的數學庫,包含110個基本數學函式的集合。
為了測試KylinX對全域性變數的更新過程,我們還向舊的和新的libyn庫添加了111個偽全域性變數以及一個read_global函式(讀出所有全域性變數)。主函式首先將全域性變數設定為隨機值,然後通過呼叫讀取全域性函式定期驗證這些變數。
因此,在我們的測試中總共有111個函式和111個變數需要更新。更新程式大致可分為 4個階段,我們測量每個階段的執行時間。
首先,KylinX將new_lib載入到dom0的記憶體中並與domU共享。其次,KylinX修改.got.plt表中函式的相關條目,以指向.plt表中的相應條目。 第三,KylinX 為每個函式呼叫du_resolve,這些函式要求dom0解析給定的函式並返回其在new_lib中的地址,然後將相應的條目更新為返回的地址。最後,KylinX將新lib的.got表中的全域性變數的相應條目解析為適當的地址。我們在評估中修改第三階段,一次更新libyn中的所有111個函式,而不是在實際被呼叫時懶惰地連結函式(第3.3.2節),以便概述libyn的整個執行時更新成本。
結果如圖7所示,其中更新所有函式和變數的總開銷約為5毫秒。第三階段(解析函式)的開銷高於其他階段,包括第四階段(解析變數),這是由第三階段中的幾個耗時的操作引起的,包括解析符號,跨域呼叫d0_ resolve,返回實際函式地址和更新相應的條目。

4.6 申請
除了pVM排程和管理的流程靈活性和效率之外,KylinX還為其容納的應用程式提供了高效能,與Ubuntu上的對應應用程式相當,如本小節所述。
4.6.1 Redis 伺服器應用程式
我們在KylinX pVM中評估Redis伺服器的效能,並將其與MiniOS/Ubuntu中的效能進行比較。同樣,由於MiniOS不支援fork(),我們暫時刪除了序列化程式碼。 Redis伺服器使用select而不是epoll來實現非同步I/O,因為 MiniOS和KylinX使用的lwIP堆疊[4]尚不支援epoll。
我們使用Redis基準[13]來評估效能,該效能使用可配置數量的繁忙迴圈來非同步寫入KV。我們為客戶端的寫請求執行不同數量的pVM/VM/程序(1個伺服器一個)。我們測量寫入吞吐量作為伺服器數量的函式(圖8)。三種Redis伺服器具有相似的寫入吞吐量(由於選擇的限制),隨著併發伺服器的數量幾乎線性增加(在lwIP堆疊成為瓶頸之前,縮放是線性的,最多8個例項)。

4.6.2 Web 伺服器應用程式
我們評估了KylinX中的JOS Web伺服器[11],它為多個連線提供多執行緒處理。主執行緒接受傳入連線後,Web伺服器建立工作執行緒來解析標頭,讀取檔案,並將內容傳送回客戶端。我們使用Weighttp基準測試來支援HTTP協議的一小部分(但對我們的Web伺服器來說足夠)來衡量Web伺服器效能。與Redis伺服器的評估類似,我們通過在一臺計算機上執行多個Weighttp [8]客戶端來測試Web伺服器,每個客戶端不斷向Web伺服器傳送GET請求。
我們將吞吐量作為併發客戶端數量的函式進行評估,並將其與分別在MiniOS和Ubuntu上執行的Web伺服器進行比較。結果如圖9所示,其中KylinX web伺服器實現了比MiniOS web伺服器更高的吞吐量,因為它提供更高的順序效能。KylinX和MiniOS Web伺服器都比Ubuntu Web伺服器慢,因為非同步選擇是使用MiniOS的網路驅動程式[27}進行低效排程的。

5 相關工作
KylinX與靜態Unikernel裝置[56,27 ],減少 VM [ 19,48,49 ],容器[66,9,15]和影象處理[38,62,32,54,67,33]有關。
5.1 Unikernel 和Redced VMs
KylinX是Unikernel[56]的擴充套件,在MiniOS [27]之上實現。Unikernel OS包括Mirage [56],Jitsu [55],Unikraft [18]等。 例如,Jitsu [55]利用Mirage [56]設計一個功能強大且響應迅速的平臺,用於在邊緣網路中託管雲服務。LightVM [58]利用Xen上的Unikernel來實現快速啟動。
MiniOS [27]設計並實現了一個C風格的Unikernel LibOS,它作為Xen域中的半虛擬客戶OS執行。MiniOS具有比Mirage更好的向後相容性,並支援用C語言編寫的單程序應用程式。但是,最初的MiniOS靜態密封裝置並且遇到與其他靜態Unikernel相似的問題。
KylinX和靜態 Unikernels( 如Mirage [56],MiniOS [27]和EbbRT [65])之間的區別在於pVM抽象,它明確地將hypervisoras作為作業系統並支援過程式操作,如pVM fork/IpC和動態庫對映。對映限制(第3.3.4節)使KylinX儘可能地引入漏洞,並且沒有比 Mirage/MiniOS 更大的TCB [56,55]。 KylinX支援原始碼(C)相容性,而不是使用型別安全的語言來重寫整個軟體堆疊[56]。
最近的研究 [19,49,48]試圖改進基於Hypervisor的型別1虛擬機器,以實現更小的記憶體佔用,更短的啟動時間和更高的執行效能。 Tiny Core Linux [19]儘可能減少現有的Linux發行版,以減少客戶的開銷。 0S0 [49]實現了一個新的客戶作業系統,用於在VM上執行單個應用程式,解析對其核心的libc函式呼叫,該核心採用優化技術,如spinlock-freemutex [70]和網路通道網路堆疊[46 ] .RumpKernel [48]通過實現優化的客戶作業系統來減少VM。與KylinX不同,這些通用LibOS設計包含針對目標應用的不必要的特徵,導致更大的攻擊面。它們不支援多程序抽象。此外,KylinX的pVM fork比SnowFlock中基於重複的VM_fork要快得多[50]。
5.2 容器
容器使用作業系統級虛擬化[66]和利用核心功能來打包和隔離程序,而不是依賴於虛擬機器Hypervisor。作為回報,他們不需要捕獲系統呼叫或模擬硬體,並且可以作為正常的OS程序執行。例如,Linux Containers(LXC)[9]和Docker [15]通過使用許多Linux核心功能(例如naynespaces和cgroups)來建立容器,以打包資源並執行基於容器的程序。
容器需要使用相同的主機作業系統API [49],從而暴露數百個系統呼叫並擴大主機的攻擊面。因此,儘管LXC和Docker容器通常比傳統VM更有效,但它們提供的安全性較低,因為攻擊者可能會破壞容器內執行的程序。
5.3 Picoprocess
picoprocess本質上是一個容器,它在主機作業系統和客戶機之間實現LibOS,將高階客戶機API對映到一個小介面上。原始的picoprocess設計(Xax [38]和Embassies [43])只允許一個微小的系統呼叫API ,它可以小到令人信服(甚至可以證實)的孤立。 Howell等。通過提供POSIX 模擬層並繫結現有程式,展示如何在最小的picoprocess介面[44]之上支援一小組單程序應用程式。
最近的研究放鬆了靜態和剛性微過程隔離模型。。例如,Drawbridge [62]是Xax [38] picoprocess的WinBows轉換,並建立了支援豐富桌面應用程式的picoprocess LibOS。 Graphene [67]擴充套件了LibOS正規化,支援在picoprocesses的一個家族(沙箱)中使用多程序API(使用訊息傳遞)。 Bascule [ 32]允許 在執行時安全有效地附加與OS無關的擴充套件。 Tardigrade [54]使用picoprocesses輕鬆構建容錯服務。這些鬆弛在picoprocess上的成功激發了我們對Unikernel的動態KylinX擴充套件。
容器和picoprocesses通常具有大的TCB,因為LibOS包含未使用的功能。相比之下,KylinX和其他Unikernel利用虛擬機器Hypervisor的虛擬硬體抽象來簡化它們的實現,並遵循極簡主義[36]僅將應用程式與必需的庫相結合,不僅提高了效率,還提高了安全性。
Dune [34]利用Intel VT-x [69]提供程序(而不是機器)抽象來隔離程序並訪問特權硬體功能。IX [ 35]將 虛擬裝置整合到Dune過程模式中,為網路系統實現了高吞吐量和低延遲。1wCs [53]在程序內提供獨立的保護,特權和執行狀態單元。
與這些技術相比,KylinX直接執行Xen(1型虛擬機器Hypervisor),自然提供強大的隔離,使KylinX能夠專注於靈活性和效率問題。
6 結論
在雲虛擬化的文獻中,長期存在強烈孤立和豐富特徵之間的緊張關係。本文利用新的設計空間,通過在高度專用的靜態Unikernel中新增兩個新特性(動態頁面和庫對映)來提出pVM抽象。簡化的虛擬化架構(KylinX)將虛擬機器Hypervisor作為OS,並安全地支援靈活的程序式操作,例如pVM fork和inter-pVM通訊,執行時更新和快速回收。
在未來,我們將通過模組化[27],分解[60]和新交所飛地[33,28,45,68] 來提高安全性。我們將通過採用更高效的執行時MUSL來改善KylinX的效能[23],並使KylinX適應Multi LibOS model [65],允許將pVM跨越多個機器。目前,pVM的回收機制還是暫時的和有條件的:它只能檢查點的空域; 迴圈的pVM無法使用事件通道或共享記憶體與其他pVM通訊; 應用程式只能採用自包含共享庫的形式,不需要載入其他共享庫; 回收後,新老pVM之間仍然沒有檢查潛在安全威脅的保障措施。我們將在未來的工作中解決這些缺點。
7 致謝
這項工作得到了中國國家基礎研究計劃(2014CB340303)和國家自然科學基金(61772541)的支援。Wethank Li Ziyang Li,Qiao Zhou和匿名評論員幫助他們完善了本文。這項工作是在第一作者訪問劍橋大學計算機實驗室的NetOS小組時進行的,我們感謝Anil Madhavapeddy 教授,Ripduman Sohan和劉浩的討論。
正文之後
搞掂,希望有用吧。。這些新點的文章網路上屁內容都沒得,國防科技大學的老師也沒得對外的聯絡方式,所以說,選了這篇文章做彙報的同學,加油~