虛擬化與容器

半虛擬化(paravirtualization)

/ PAIR-uh-vir-choo-al-eye-ZAY-shun /

完全機器虛擬化費盡力氣徹底騙過客體——客體未經修改地執行,從不知道自己被虛擬化。半虛擬化做的是相反的交易:它對客體說實話,並請它配合。客體的作業系統被修改,使它不再執行特權硬體指令、然後指望超管理器逮住,而是禮貌地直接呼叫超管理器、請它提供所需。「Para」意為「在旁、並肩」——客體與超管理器並肩工作,而非被它蒙騙。

具體而言,被修改過的客體把一連串昂貴的、會引發陷阱的操作,換成對超管理器的明確呼叫,叫做超呼叫(hypercall,虛擬化界的系統呼叫類比——一個刻意、快速、從客體跨進超管理器的請求)。舉例來說,半虛擬化的客體不再發出許多各自陷入的分頁表更新,而是把它們成批起來、做一次超呼叫:「請套用這二十個映射。」它也不再假裝有個磁碟控制器、再逐位元組地模擬它的暫存器,而是讓半虛擬化驅動與超管理器共享一個環狀緩衝區、說「這裡有十個排隊的請求」。在 x86 上把這做法發揚光大的專案 Xen,正是因為經典 x86 並非經典可虛擬化才採用半虛擬化——它透過修改客體、使其絕不盲目使用那些「逮不到」的指令,從而避開了它們。

它為何重要、以及它誠實的限制:半虛擬化可以遠快過天真的完全虛擬化,因為「配合」消除了整片整片的 VM-exit 風暴——客體與主機照著一套共享、有效率的協定工作。代價是可移植性:一個半虛擬化的客體需要一個被修改過的作業系統,所以你沒辦法用這種方式啟動一個未經修改、現成的 OS。一旦硬體輔助虛擬化讓未經修改的客體跑得快,對「整台機器」的純半虛擬化便退潮了——但那個「配合」的點子存活了下來,並在一個地方勝出:半虛擬化「裝置」,也就是 virtio 模型,CPU 跑的是未經修改的客體,但驅動程式為了速度而彼此配合。

半虛擬化驅動不再為每個封包寫入一個被模擬的網路卡暫存器(每次寫入都陷入主機),而是把要送出的封包放進一個共享的環狀緩衝區,再做一次超呼叫說「處理這個佇列」,把上千次退出變成一次。

配合讓客體把工作成批塞進一次超呼叫,而不必每個操作都陷入。

純粹的整機半虛擬化需要一個被修改過的客體作業系統,所以無法啟動現成的作業系統——這個限制正是硬體輔助虛擬化在 CPU 層取代它的原因。那個「配合」的點子如今主要活在半虛擬化「裝置」(virtio)裡,而非活在半虛擬化整顆 CPU 上。

又稱
PVcooperative virtualization協作式虛擬化