2015年4月20日 星期一

明智消費者的虛擬化技術基本觀念及術語

[閱讀本文可搭配 這份 sozi 簡報。 操作方式請見 這裡]

本文是資訊人權貴為明智的消費者所寫的虛擬化技術簡介, 也試圖將虛擬化常用術語一網打盡。 作者本身虛擬化實作經驗不多, 只略熟 proxmox qemu。 (感謝學生當白老鼠沒抗議) 但是爬了好幾十篇文章。 歡迎留言指正錯誤 and/or 提供遺漏的虛擬化常用名詞。

一、 簡介

虛擬化 (Virtualization) 技術讓你可以用一部實體電腦假裝成好幾部電腦。 例如透過虛擬化技術, 你可以在 Linux 電腦上面開一部 Windows 電腦跟一部 Android 平板 來玩。 實體電腦開機時, 掌管電腦的那個作業系統 (上例中的 Linux) 稱為 Host Operating System; 後來從 host OS 裡面啟動的那些虛擬機, 上面所跑的作業系統 (上例中的 Windows 跟 Android) 則稱為 Guest Operating Systems。 Host OS 裡面負責管理虛擬機的那支程式稱為 HypervisorVirtual Machine Monitor (VMM)。 例如 qemu 跟 VirtualBox 都是 hypervisor。 又, 在虛擬化文件裡, 當我們特別要強調實體機 (有別於虛擬出來的硬體) 的硬體部分 (不含作業系統) 經常被稱為 bare metal

  1. 「初探虛擬機和虛擬化」 by FreedomKnight
  2. 「虛擬的世界: 談現代化機房管理」 by 朱孝國
  3. 「虛擬技術及應用」 by 張保榮 (高雄大學教授)
  4. 英文維基百科

二、 虛擬化簡史

早在 1960 年代, IBM 就為他們的 mainframe 大型主機開發出虛擬化技術。

至於 PC 上的虛擬化, 一個重要里程碑是 Intel 在 1985 年推出的 80386。 透過 virtual 8086 mode enhancements 這個新機制, 在一部 80386 電腦上, 可以開啟多部彼此獨立的 8086 虛擬機。 任何一部當掉, 都不會影響其他部, 也不會影響底層的 host OS。 IBM OS/2 2.0 在 1992 年開始善用這個功能。 所以 IBM 說得沒錯, 它是是一個 「better windows than windows」, 因為它可以同時開啟多個 Windows 3.0 。 微軟要到 Windows 95 年代 才跟上腳步。 在今日任何 x86 的 cpu 上面下 egrep --color=auto vm /proc/cpuinfo 指令, 都會看到至少有 vme 這個旗標, 這就是 virtual 8086 mode。 在 linux 底下, 可以用 dosbox 開啟 DOS 虛擬機。

然後有很長一段時間大家就不再談虛擬化了。 反正硬體很便宜。 需要新的 server? 再買一部就好。 直到 server 越來越多、 既浪費電跟空間又難管理, 大家才開始談 server consolidation 伺服器整併。 一種方式是把 ftp 伺服器、 資料庫伺服器、 網頁伺服器、 DNS 伺服器、... 通通放在同一部電腦的同一個作業系統裡面。 但它們可能彼此互相干擾、 有些服務甚至可能要求綁定特定版本的作業系統或資料庫, 總之就算辦得到, 管理起來可能也會變得很麻煩。

另一種比較最簡單的方式就是把每部實體伺服器都變成一部虛擬機, 這樣就可以讓它們共存於同一部實體機上, 又彼此互不干擾。 把一部伺服器從實體機轉換成虛擬機的過程叫做 Physical to Virtual (P2V) migration。 整併之後有以下好處:

  1. 提高硬體使用效率。
  2. 自動享有 Load Balancing (負載平衡)
  3. 備份變得更容易。
  4. 硬體升級變得更容易。

也請參考 Networks and Servers: Server Virtualization Explained

三、 虛擬化的挑戰

在多工環境底下, 為了隔絕不同 processes、 讓不同的應用程式彼此互不干擾, x86 的 CPU 提供了一個 protection rings 的機制。 在 linux 底下, 一般的程式在做加減乘除或是讀寫 「屬於自己的記憶體」 時, 是在 user mode 模式底下執行, 也就是被 OS 限定只准採用 ring 3 最低權限模式。 至於涉及硬體/輸入輸出的動作, 有一大部分都在 kernel mode 模式底下執行, 也就是切換到 cpu 的 ring 0 最高權限模式。 所以只要 kernel 寫得好, 一般的 apps 再怎麼亂來, 系統也不致於當掉。

當你要對一個作業系統進行 P2V 時, 問題就來了。 不論是 windows 或 linux, OS 習慣獨霸整部機器、 完全掌控 ring 0 最高權限; 現在底下卻又多了一層 hypervisor 要限制它直接存取硬體 (這是一定要的, 以免它跟其他 guest OS 互相干擾), 這叫 guest OS 情何以堪? 有些 hypervisor (例如 VirtualBox vmware) 採用 binary translation 技術: 把 guest OS 原本想在 ring 0 執行的程式碼偷偷搬到 ring 1, 然後隨時監督著 guest OS, 每當 它執行到 「需要 ring 0 權限」 的特殊指令時, 就跳出來接手管理。 效率當然不太好。 有時特別為了跟以下的 paravirtualization 或 hardware assisted virtualization 區別, 這種方式又稱為 full virtualization without hardware assist

要提升效率, 有幾種不同的解決方案。

四、 省略 Host OS

在大公司的機房, 反正 host OS 上面除了 hypervisor 之外, 又不需要跑其他任何 apps, 所以何不乾脆把 host OS 整個省略掉? 當然, 此時 hypervisor 底下沒有 OS 替它服務, 所以它必須自立自強、 自己 (或是搭配某個 kernel) 管理所有的硬體與週邊。 這種 hypervisor 稱為 Type I (Bare Metal) hypervisor。 例如 VMware ESXi 跟 Citrix XenServer 都屬於 Type I hypervisor。 進階閱讀: ESXi 與 linux 之間的關係

相對地, 我們平常在自己桌機或筆電上面, host OS 總是會拿來開瀏覽器、 文書處理、 聽音樂、 ... 等等各種 apps, 所以 host OS 不能省略。 在這樣的環境底下運作的 hypervisor 稱為 Type II hypervisor

不過, 讓效率下降最多的主因, 其實是客人把主人家當自己家、 恣意使用特權。 砍掉 host 的做法, 就像是主人節節退讓、 允許喧賓奪主, 雖然也可以提升一些效率, 但我個人覺得, 這有點像是左腳在癢卻猛抓右腳。

五、 硬體加持

要解決舊硬體所帶來的挑戰, 最直接、 有效的方法就是針對問題推出新硬體。 比較新的 CPU 多了一個 「ring -1」, 也就是比 ring 0 的權限更高的模式。 在這樣的電腦下, guest 跟 host 都不必退讓。 當 guest OS 執行 ring 0 特殊權限指令時, 硬體會自動 (而不需要靠 hypervisor 用一些特殊技巧來達成) 捕獲控制權, 將控制權交給 hypervisor。

在 linux 底下, 可以用 egrep --color=auto 'svm|vmx' /proc/cpuinfo 指令來查看你的 cpu 是否提供 Hardware-Assisted Virtualization。 若看到 svm, 那麼你擁有一顆支援硬體虛擬化的 AMD-V cpu; 若看到 vmx, 那麼你擁有一顆支援硬體虛擬化的 Intel VT-x cpu。 使用 qemu-system-x86_64 指令時, 要加上 -enable-kvm 旗標, 才會啟用 hardware-assisted virtualization。

更進一步, 如果 cpu 還支援 Second Level Address Translation 記憶體管理虛擬化的功能, 效果會更好。 Intel 的版本叫做 Extended Page Table; 在 /proc/cpuinfo 裡面以 ept 旗標呈現。 AMD 的版本原先叫做 Nested Page Table, 後來改名為 Rapid Virtualization Indexing; 在 /proc/cpuinfo 裡面 以 npt 或 rvi 呈現

再進一步, 如果 cpu 支援 巢狀虛擬化 nested virtualization, 那麼在 guest 裡面還可以看見上述旗標, 所以在 guest 裡面可以繼續用硬體加速的方式再開一層 guest... 你可以玩 虛擬機俄羅斯套娃! 在貴哥不太豐富的虛擬化經驗裡, amd 的 cpu 比 intel 的 cpu 更適合玩巢狀虛擬化。

當然, 若是 guest OS 期待不同的硬體, 那麼硬體加速就無效了。 例如 android sdk 的模擬器要在 x86 的機器上模擬 arm 的 CPU, 當然就龜速。 至於 android-x86 則是省略 arm, 直接在 x86 上面架 JVM, 於是硬體加速有效, 雙重優勢下, 速度當然快很多。

六、 Guest 自主釋權

在硬體解決方案出現之前, 已有很多團隊嘗試軟體解。 既然問題的根源在於 guest OS 會去動用最高權限, 那麼如果 guest OS 願意放下身段, 承認自己不是老大, 事情就好辦得多。 當它需要用到某些 (ring 0 才准用的) 敏感指令或敏感資源時, 放棄 「硬是要親手直接執行特殊指令」 的做法, 而是 "自主釋權" 改呼叫 hypervisor 委請 hypervisor 來幫它完成 (這動作稱為 hypercall)。 這種安排方式叫做 paravirtualization

也就是說, paravirtualization 必須搭配特殊修改過的 guest OS 來使用。 所以諸如 linux 之類開放原始碼的作業系統比較容易實現 paravirtualization。 lguest 是一個例子。 Xen 則是 linux 上 最早 (也請見 這裡) 同時可能也是最主流的 paravirtualization hypervisor。

因應硬體加速趨勢, VMWare 正在 淘汰 paravirtualization

但事實上 paravirtualization 跟 hardware-assisted virtualization 並不是二選一的互斥技術。 兩者可以搭配使用, 更加提升效率。 也就是說, paravirtualization 還可以分程格雷的五十道陰影... 呃, 我是說 xen 的 「虛擬化光譜」 有五六種不同程度的「自主釋權」

七、 完全弱勢低調的 Guest OS

Guest OS 都已經很知趣地自主釋權了, 不如就好人做到底吧。 乾脆跟 host OS 融合, 共用同一個 kernel, 省略了 「虛擬硬體」 的層級, guest OS 的其他工作都很低調地在 user mode 執行, 完全 「客隨主便」, 這就變成了 container。 知名的 container 技術包含:OpenVZ、 lxc、 以及最近很紅的 docker。 Container 的優點: 不需要硬體支援也可以飛快效率不打折。 Container 的缺點: 必須跟 host OS 共用 kernel。

八、 難以歸類的虛擬技術

其實虛擬化技術分類很難很精確, 因為 「虛擬化」 牽涉很多問題要處理 (CPU、 記憶體、 interrupt、 硬碟、 網路、 ...), 而每個問題都有很多不同的處理方式, 所以其實有很多不同的排列組合, 遇到一個軟體, 有時也很難百分之百將它歸類其中某一類。 例如 User Mode Linuxcolinux 兩者通常被歸類為 paravirtualization。 但顯然他們並不是在 kernel mode mode 底下執行, 所以就這點而言, 他們又略帶一點 container 的特性。 此外, 兩者都不需要另外搭配 hypervisor, 所以 有人認為: 談論 paravirtualization 時, 也要考慮 「省略 hypervisor」 的狀況才算完整。 (colinux 讓你可以在 windows 底下執行 linux。)

此外, 有很多虛擬化軟體更是支援不只一類的虛擬方式。 例如 qemu, 如果加了 -enable-kvm 就是 HW-assisted virtualization; 如果沒加就是 full virtualization without hardware assist。 當你下 qemu -enable-kvm 指令時, 其實 qemu 並不是完整的 hypervisor -- 核心的 kvm 模組 (加上 kvm_amd 或 kvm_intel 模組) 也應該算是 hypervisor 的一部分。

至於 libvirt 這類軟體, 它本身不是 hypervisor, 而是資源及各種 hypervisors 的協調管理者。 但是 qemu (或 OpenVZ 或其他 hypervisor 關鍵技術) 少了它們, 就像 VirtualBox 或 VMWare 少了圖形介面一樣, 感覺上不太完整。

還有 OpenStack 這又是另一大門學問。 其中的 Nova Compute 元件用到 libvirt。

也就是說, 在某些場合看到大家對於虛擬化技術名詞有歧見, 除了誰對誰錯之外, 還有一種可能是: 雙方說的都有道理。 這時或許可以推薦 「xen 的光譜」 那篇文章請雙方參考。

九、 採購虛擬化技術前必讀

[6/10 補充本節] 如果你需要把舊的伺服器做 P2V, 有時可能還是必須採用完整的虛擬化技術。 這裡有幾個 「可選用的虛擬化技術清單」:

  1. Compare Virtualization Software & Hypervisors
  2. Comparison of platform virtualization software

至於建立新的伺服器, 當然選擇輕量級的 container。 Linux Containers: Parallels, LXC, OpenVZ, Docker and More 這篇列出一些可選用的 container 技術。 如果需要一個比較完整自主的 (輕量級) 主機環境, 我覺得用 proxmox 上面的 OpenVZ container 最簡單; 2015 的流行趨勢則是採用 docker -- 一個 container 只跑一個服務 (例如網頁伺服器可能就跟資料庫伺服器拆開放在兩個 dockers 裡面來跑)。

  1. Docker switches from LXC to their own libcontainer
  2. Docker inside OpenVZ CT
  3. OpenVZ VS Docker,不火只是时机的错吗?
  4. difference between docker and openVZ

十、 結論

當你面臨 P2V 的工作, 你需要做出兩大決定: (1) 要採用哪個 OS 作為 Host? (2) 要採用哪一種虛擬技術? Linux 與 Windows 作為 host 或 guest 總共有四種組合:

Linux Guest Windows Guest
Linux Host 多種 container 技術可選, 效率超高 必須採用 full virtualization
Windows Host docker for windows 其實還是需要 full virtualization; 最多做到 paravirtualization, 例如 colinux Windows Server Container

Guest OS 當然沒得選 -- 基本上它必須跟你想要虛擬化的實體機一樣。 (如果你們當初選擇的 software stack 都是跨平臺的, 那就另有彈性。) 不過我們可以回顧一下當初你們公司的選擇是否明智。 不論 host 是誰, linux guest 所面臨的選項總是比 windows guest 所面臨的選項彈性更大。 原因很簡單: windows 沒有原始碼, 所以 「可以提高虛擬化效率的途徑」 少了很多。 此外, linux 要做 P2V 比 windows 要容易許多。 因為 windows 要 「保護智慧財產權」, 所以不能讓你輕易把 OS 搬來搬去; 相形之下, 隨遇而安的 linux 拷貝過去之後, 只需要改兩個設定檔就 OK 了。

回到原來的問題。 從執行效率來講, 如果能夠選擇低調隨和的 container 當然是最理想的。 也就是左上角的 linux guest over linux host 或是右下角的 windows guest over windows host。

但是 server consolidation 的過程, 很可能會同時遇到兩種 (甚至其他更多種) guests。 你現在所做的選擇, 還會影響到未來 guest 的選擇。

所以你到底該如何選擇 host? 要選擇上列還是下列? 提示一: 選擇哪一種 host 可以讓你未來更有動力與機會選擇高效率的 guest? 提示二: 左上跟右下比, 右上跟左下比。 (請注意: docker 到了 windows 上, 還是需要 full virtualization, 已經 失去了 container 天生的大部分優勢。 橘生淮南則為橘; 生於淮北則為枳啊!) 這時你們的 CIO 或電算中心主任終於會開始理解何謂 下賊船的代價

十一、 更多參考資料

  1. Hardware-Assisted Virtualization Explained
  2. In-depth Overview of x86 Server Virtualization Technology
  3. Virtualization Basics
  4. CPU Rings, Privilege, and Protection
  5. 搜尋 「x86 protection rings」
  6. Virtualization in Linux KVM + QEMU
  7. Intro to the Paravirtualization Spectrum With Xen (Part 2)

[感謝 恆逸資訊洪朝欽老師 指正本文並補充資訊。]

2 則留言:

  1. 您這篇虛擬化技術的文章寫的真好,其他人沒有加以解釋的東西您都有詳細的寫出來。

    回覆刪除
  2. 啊 是 vixual 大 :-) 抱歉今天才注意到 ^_^||| 小格也引用了您的好幾篇好文。

    回覆刪除