虛擬機器中的檔案系統效能比較
多年來,對於使用 Vagrant 的虛擬機器開發環境而言,主要的效能瓶頸一直是檔案系統效能。CPU 的差異極小,幾乎感受不到,而 RAM 只有在同時執行多個虛擬機器時才會成為問題。
我花了昨天大部分的時間對常見的檔案系統機制進行基準測試與分析,並在此與大家分享測試結果。
我將先從結果分析開始,因為這是大多數人最感興趣的部分。確切的測試方法、使用的軟體以及原始數據,都可以在此分析下方找到。
在下方顯示的每一張圖表中,我們都以某種方式測試檔案的讀取或寫入。每張圖表所寫入檔案的總大小是固定的。Y 軸是以 KB/s 為單位的傳輸量,X 軸則是「record size」,也就是一次讀取/寫入的資料區塊大小,單位為 KB。
不同的測試環境包括 native、VirtualBox native、VMware native、VirtualBox shared folders(vboxsf)、VMware shared folders(vmhgfs)以及 NFS。「native」環境指的是在該環境中單獨使用檔案系統。「native」是在主機上,「VirtualBox native」則是在 VirtualBox 虛擬機器內的根裝置上,以此類推。NFS 僅在 VirtualBox 上進行測試,因為其效能特性在 VirtualBox 與 VMware 上應該是相似的。
對於每一張圖表而言,傳輸量(Y 軸)越高越好。
小檔案循序讀取
首先是對一個 64 KB 檔案進行循序讀取,並測試不同的讀取 record size。在現實世界中,小檔案循序讀取的應用場景可能是載入應用程式的原始碼檔案以便執行、編譯或測試。

首先令人無法忽視的是,NFS 在較小的 record size 下,讀取效能表現得非常出色。NFS 很可能是透過大量的 read-ahead(預讀) 操作與快取來達到這種效能。我目前沒有一個合理的解釋來說明 NFS 為何能超越原生的虛擬檔案系統。
在這個項目中,VMware shared folders 徹底擊敗了 VirtualBox shared folders。VirtualBox shared folder 的讀取效能簡直慘不忍睹。如果你查看原始數據,會發現其傳輸量實際上從未超過 100 MB/s,而 VMware 的傳輸量則從未低於 500 MB/s,峰值甚至超過 900 MB/s。
有趣的是,虛擬機器內的原生檔案系統有時反而優於主機上的原生檔案系統。這項測試使用的是未經任何使用者空間緩衝的原始 read 系統呼叫。很有可能是 hypervisor(虛擬機器監視器) 對來自虛擬機器的讀取操作進行了緩衝,因此透過減少切換至原生核心的次數而獲得了更好的效能。查看 fread 基準測試的原始結果數據可以進一步支持這個推論。在那些測試中,原生檔案系統每次都勝過虛擬檔案系統。
大檔案隨機讀取
這項測試測量的是隨機讀取一個 64 MB 檔案中不同區塊的傳輸量,同樣以不同的讀取 record size 進行測試。這個檔案比前一次測試的檔案大了 1000 倍。這種行為模式可能會在處理會存取檔案系統的資料庫讀取時出現。

相較於小檔案循序讀取,VMware shared folders 與 VirtualBox shared folders 之間的差距在此被大幅拉大。VirtualBox 的表現非常糟糕,甚至在圖表上幾乎看不到它。同樣地,VirtualBox 的傳輸量峰值從未超過 100 MB/s。相反地,VMware 的峰值則高達 7 GB/s。由於 VirtualBox 的傳輸量在各種測試案例中的變化極小,我推測 VirtualBox 共享資料夾系統中存在單一的熱點程式碼路徑限制了效能。他們顯然在某個環節上出了問題。
NFS 的優勢在此不再那麼明顯,很可能是因為在此測試案例中無法體現預讀帶來的好處。即便如此,相較於其他選項,NFS 的表現仍然非常出色。
而且,就像小檔案循序讀取一樣,我們仍然看到虛擬機器內部的效能優於外部。同樣地,這可以歸因於 hypervisor 進行了巧妙的緩衝,而對主機的原始系統呼叫則無法做到這一點。
小檔案循序寫入
接下來看看小檔案循序寫入的效能。這最能準確地描述儲存工作階段狀態、暫存檔或寫入新原始碼檔案的情境。

首先引人注目的是,NFS 在這類寫入操作的效能非常糟糕。NFS 在此無法進行有效的快取,因此你必須承擔完整的代價:網路開銷、接著在主機端寫入磁碟,最後還要等待虛擬機器收到寫入成功的 ack。真是慘不忍睹。
各種「native」檔案系統的表現都非常好。同樣地,虛擬機器的效能優於主機。這同樣可以歸因於 hypervisor 中的緩衝機制。
共享檔案系統之間的表現相近,但在這個測試案例中,VirtualBox 明顯優於 VMware。
大檔案隨機寫入
我們要看的最後一張圖表,是對一個大型(64 MB)檔案進行隨機寫入的測試結果。就像我們的大檔案隨機讀取測試一樣,這是衡量資料庫效能表現的一項良好測試。

與小檔案循序寫入相比,這裡其實沒有太大的差異。由於是大型檔案,不同測試環境之間的差距更大,但除此之外,結果大致相同。
NFS 在寫入方面依然表現糟糕。在寫入方面,VirtualBox shared folders 持續優於 VMware,而 hypervisor 的效能則優於主機。
hypervisor 效能優於主機這點對我來說是最有趣的。這項測試的結果清楚地顯示,為了效能,hypervisor 一定在 synced writes(同步寫入) 上說了謊。這也印證了我在 Packer 上看到的情況:若虛擬機器未正常關機,已提交的寫入就會遺失。在虛擬機器中執行 fsync() 並不代表資料已寫入主機,僅代表資料已在 hypervisor 內提交。
整體分析
就共享檔案系統而言,VMware 擁有你想要的特性。載入網頁、執行測試套件以及編譯軟體等操作,都是以讀取為主。VMware 共享資料夾的讀取效能徹底擊敗了 VirtualBox,而 VirtualBox 共享資料夾的寫入效能僅比 VMware 略好一些。
如果你有使用 NFS 的選項,就使用它吧。同樣地,讀取效能遠比寫入效能來得重要。
hypervisor 的讀寫效能非常出色(因為它們作弊了)。多虧了這些數據,我肯定會更加專注於 Vagrant 中僅使用原生檔案系統的新 synced folder 實作(例如 rsync,或是將主機作為 NFS client 而非 server 來使用)。
然而,更具即時應用價值的建議是:如果你使用虛擬機器進行開發,請盡可能將資料庫檔案移出共享檔案系統。你很可能會看到巨大的效能提升。
最後,我認為這些結果並沒有帶來太大的驚喜。Vagrant 自 2010 年以來就已支援 NFS synced folders,因為我們很早就意識到共享資料夾的效能不佳。但能夠擁有一些具體數據來展示不同的行為模式還是很有價值的,也為每個系統可能的運作方式提供了有趣的洞見。
隨機一篇部落格