Run a Kata Container utilizing virtio-fs Once installed, start a new container, utilizing qemu + virtiofs: $ docker run --runtime=kata-qemu-virtiofs -it busybox Verify the new container is running with the qemu hypervisor as well as using virtiofsd. To do this look for the hypervisor path and the virtiofs daemon process on the host: $ ps -aux | grep virtiofs root ... /home/foo/build-x86_64_virt/x86_64_virt-softmmu/qemu-system-x86_64_virt ... -machine virt,accel=kvm,kernel_irqchip,nvdimm ... root ... /home/foo/build-x86_64_virt/virtiofsd-x86_64 ... You can also try out virtio-fs using cloud-hypervisor VMM: $ docker run --runtime=kata-clh -it busybox
1. 當前安全容器存儲領域的問題
在介紹virtio-fs之前,我們先來了解一下當前安全容器存儲領域遇到的問題,因為只有在理解了所要解決的問題才能更好的理解解決問題的方案。
在當前安全容器領域,Kata Containers可以說是最被廣泛應用的容器技術了。Kata Containers使用輕量級虛擬機和硬件虛擬化技術來提供更強隔離,以構建安全的容器運行時。但也正是因為使用了虛擬機,容器的根文件系統(容器rootfs)無法像runc那樣直接使用主機上構建好的目錄,而需要有一種方法把host上的目錄共享給guest。
目前基本上只有兩種流派的方法能夠透傳host目錄/數據給guest,一種是基於文件的方案,一個是基於塊設備的方案。而這兩種流派又都有各自有自身的優缺點,這里分別以9pfs和devicemapper為例來說明。
- 基於文件的9pfs
- 優點:因為使用host上overlayfs,能充分利用host pagecache;部署簡單,不需要額外的組件
- 缺點:基於網絡的協議,性能差;POSIX語義兼容性方面不好(主要體現在mmap(2)的支持上,在特殊情況下有數據丟失的風險)
- 基於塊設備的devicemapper
- 優點:良好的性能;很好的POSIX語義兼容性
- 缺點:無法充分利用host pagecache,部署運維復雜(需要維護lvm volume)
可以看到,這兩種流派優缺點基本互補。那么有沒有一種解決方案能夠結合兩者的優點,同時能夠克服兩者的缺點呢?virtio-fs正是這種新的方案,為我們帶來了新的曙光。
2. virtio-fs介紹
2.1 基本信息
virtio-fs是紅帽在2018年12月10號在kata社區提出的一種在guest之間共享文件系統的方案。 項目主頁:https://virtio-fs.gitlab.io/ 代碼倉庫:https://gitlab.com/virtio-fs 郵件列表:https://www.redhat.com/mailman/listinfo/virtio-fs
其主要設計目標為:
- 在不同guest之間,以快速、一致、安全的方式共享同一個host目錄樹結構
- 擁有較好的性能和跟本地文件系統(如ext4)一樣的語義
主要使用場景:
- 在kata-container場景中替換9p,作為容器rootfs
- 為虛擬機在host和guest之間共享數據 (shared file system for virtual machines)
- File-system-as-a-Service,更安全
2.2 原理與架構設計
virtio-fs方案使用FUSE協議在host和guest之間通信。在host端實現一個fuse server操作host上的文件,然后把guest kernel當作fuse client在guest內掛載fuse,server和client之間使用virtio來做傳輸層來承載FUSE協議,而不是傳統結構上的/dev/fuse設備。為了支持在不同guest中同時mmap(MAP_SHARED)同一個文件,virtio-fs把文件mmap進qemu的進程地址空間並讓不同guest使用DAX訪問該內存空間,這樣就繞過了guest pagecache達到不同guest都訪問同一份數據的目的,同時也在多個guest之間共享了內存,節省了內存資源。
簡要架構圖:
從圖中我們可以了解到,virtio-fs主要由以下幾個組件組成:
- guest kernel:作為fuse client來掛載host上導出的目錄
- qemu:新添加的vhost-user-fs-pci設備用於在guest kernel和virtiofsd之間建立起vhost-user連接
- virtiofsd(同樣在qemu倉庫中):host上運行的基於libfuse開發的fuse daemon,用於向guest提供fuse服務
下圖是更詳細的架構圖
virtio-fs跟其他基於文件的方案(比如9pfs或者NFS)相比,其獨特之處在於virtio-fs充分利用了虛擬機和hypervisor同時部署在一個host上的特點以避免昂貴的VMEXITS。具體來說就是,DAX數據訪問和元數據的共享內存訪問都是通過共享內存的方式避免不必要的VM/hypervisor之間通信(在元數據沒有改變的情況下),而共享內存訪問也比基於網絡文件系統協議訪問要更輕量級也有更好的本地文件系統語義和一致性。這也是基於FUSE設計virtio-fs而不是基於其他網絡文件系統協議做改進的原因。
了解virtio-fs原理與設計架構之后,我們可以總結出virtio-fs的幾條設計要點,看其是如何同時擁有9pfs和devicemapper方案的優點,同時克服它們的缺點的:
- FUSE協議而不是基於網絡的協議:更快的性能,更好的POSIX語義兼容性
- 獨立的virtiofsd進程:更安全,且不需要維護單獨的塊設備(相比9pfs多了一個組件,但維護成本比devicemapper還是要小很多)
- Host/guest之間共享內存(DAX):進一步提升性能,同時節省內存資源
2.3 使用方法
說了這么多virtio-fs的好處,那么現在就來看看如何使用它吧。按照官方QEMU howto文檔里描述的步驟即可。這里需要注意的是編譯guest kernel的時候要確保打開了以下內核選項。
CONFIG_VIRTIO
CONFIG_VIRTIO_FS
CONFIG_DAX
CONFIG_FS_DAX
CONFIG_DAX_DRIVER
CONFIG_ZONE_DEVICE
- 首先運行virtiofsd,其中cache_size=4G表示DAX window大小
virtiofsd –o source=/export/source –o vhost_user_socket=/tmp/vhost-fs.socket,cache=none,cache_size=4G
- 然后啟動guest,注意 tag=myfs 選項,mount時需要tag一致
qemu-system-x86_64 –chardev socket,id=char0,path=/tmp/vhost-fs.socket –device vhost-user-fs-pci,chardev=char0,tag=myfs,cache-size=2G …
- 最后在guest中mount virtio-fs
mount –t virtiofs myfs /mnt/virtiofs
2.4 社區狀態及主要貢獻者
virtio-fs從出現開始到現在經歷里以下幾個里程碑:
- 2018-12-10:RFC patch發布
- 2019-04-12:v0.1版本發布
- 2019-05-03:v0.2版本發布
- 2019-08-19:v0.3版本發布
- 2019-08-26:virtio-fs進入v5.4-rc2內核主線(不包含DAX相關代碼)
到目前為止(2019-11)只有virtio-fs使用virtio傳輸FUSE協議部分的代碼進入了內核主線,DAX相關修改沒沒有進入,qemu的代碼已經發到qemu社區review,預計進入qemu主線不會太遠了。
virtio-fs的最主要貢獻者當然還是發起者和維護者紅帽,除紅帽之外我們阿里巴巴是最大的貢獻者了,下圖是v0.3版本發布的時候,維護者在郵件里列出的感謝列表,可以看到阿里巴巴占了很大比重。
3. virtio-fs性能及優化
說了virtio-fs這么多好話,那它實際的性能到底如何,就讓我們來實際看一看,俗話說,是騾子是馬拉出來遛遛。
3.1 性能數據
首先看一下維護者在v3 patch中給出的性能數據,我選取了其中部分數據做出圖表(v3 patch中有詳細測試設置與說明)。從圖中我們可以看出virtio-fs對9pfs呈現出碾壓式的優勢。
當然,這只是benchmark的數據,那么實際使用起來效果如何呢?我們選取了build kernel這個工作中會經常用到的workload來實際測試,從下圖可以看出,virtio-fs相比9p還是有明顯的優勢。
3.2 找到問題
從virtio-fs作者發出的v3 patch中也可以看出,測試的場景是一個相對理想的環境,也就是DAX做映射的window大小正好能夠容納測試文件的大小,作者也提到,當window大小小於文件大小的時候,會出現性能變慢的問題,因為這個時候virtio-fs需要做頻繁的DAX window管理操作。
為了調查host pagecache和DAX window操作對性能到底有多大的影響,我們設計了4中場景,分別做測試,拿到數據作為分析的基礎。這四種場景是:
- case1: 沒有命中host page cache,且需要構建dax window的映射;
- case2: 沒有命中host page cache,但不需要構建dax window映射;
- case3: 命中host page cache ,但需要構建dax映射;
- case4: 命中host page cache,且不需要構建dax映射;
測試結果如下:
從測試結果來看,host pagecache和DAX window操作都對性能有巨大的影響,所以當某個workload需要頻繁操作DAX window的時候,性能會有比較大的回退。我們在實際測試當中也遇到了這樣的case,就是當DAX window大小小於文件大小時做隨機讀測試,比如DAX window為2G,文件大小為5G的情況下,virtio-fs隨機讀性能甚至還不如9pfs。
3.3 性能優化
既然找到了問題,那么就有優化的方向和空間了。我們主要的優化方向也是在DAX window操作方面。下面分別列出我們在virtio-fs性能方面的優化,有些patch已經進入maintainer tree,有些還在review中。
3.3.1 fuse: Get rid of inode lock in range reclaim path
- Reclaim DAX mapping不需要獲取inode lock,而引入引用計數,減少inode lock上的競爭
- 當mapping的引用計數大於1時,reclaim線程略過這個映射
- 在rand-read情況下性能有x10+倍的提升 (cache-size=2G, filesize=5G)
- https://gitlab.com/virtio-fs/linux/commit/a2c5838fb76c4634634b932db6dcabfd267842bc
3.3.2 virtio-fs: do not removemapping if dmap will be used immediately
- inline/direct reclaim時不發送removemapping請求,減少vmexit次數
- 在rand-read情況下性能有近2倍的提升 (cache-size=4G, filesize=10G)
- 由於存在deadlock風險,還沒有merge
- https://www.redhat.com/archives/virtio-fs/2019-August/msg00141.html
3.3.3 virtiofs: FUSE_REMOVEMAPPING remove multiple entries in one call
- 減少removemapping請求的數量,如 truncate –s 0 testfile
- https://www.redhat.com/archives/virtio-fs/2019-May/msg00058.html
3.3.4 virtiofsd: enable PARALLEL_DIROPS during INIT
4. 總結
virtio-fs有着良好的POSIX兼容性和性能,而且是為安全容器量身打造的容器存儲解決方案,解決了該領域長期以來的痛點,可以預見virtio-fs一定會成為安全容器存儲領域下一個熱點。但其還處於早期開發階段,仍然有大量工作需要做,比如加入多隊列的支持、補足運維能力(熱升級等)、增強穩定性等等。
目前除了紅帽之外,已經有阿里巴巴、Intel、Fujitsu、華為和ARM等廠商都對virtio-fs有濃厚的興趣並且已經開始參與社區開發和測試,其中我們阿里雲操作系統組-袋鼠團隊又是除紅帽之外最大的貢獻者。也歡迎感興趣的同學們趕緊行動起來,來貢獻bug report和patch吧!